@@ -21,6 +21,7 @@ use check::{check_expr_with_lvalue_pref};
21
21
use check:: { instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type} ;
22
22
use require_same_types;
23
23
use util:: nodemap:: FnvHashMap ;
24
+ use session:: Session ;
24
25
25
26
use std:: cmp;
26
27
use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
@@ -136,6 +137,12 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
136
137
}
137
138
hir:: PatEnum ( ..) | hir:: PatIdent ( ..)
138
139
if pat_is_resolved_const ( & tcx. def_map . borrow ( ) , pat) => {
140
+ if let hir:: PatEnum ( ref path, ref subpats) = pat. node {
141
+ if !( subpats. is_some ( ) && subpats. as_ref ( ) . unwrap ( ) . is_empty ( ) ) {
142
+ bad_struct_kind_err ( tcx. sess , pat. span , path, false ) ;
143
+ return ;
144
+ }
145
+ }
139
146
let const_did = tcx. def_map . borrow ( ) . get ( & pat. id ) . unwrap ( ) . def_id ( ) ;
140
147
let const_scheme = tcx. lookup_item_type ( const_did) ;
141
148
assert ! ( const_scheme. generics. is_empty( ) ) ;
@@ -192,11 +199,12 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
192
199
}
193
200
hir:: PatIdent ( _, ref path, _) => {
194
201
let path = hir_util:: ident_to_path ( path. span , path. node ) ;
195
- check_pat_enum ( pcx, pat, & path, Some ( & [ ] ) , expected) ;
202
+ check_pat_enum ( pcx, pat, & path, Some ( & [ ] ) , expected, false ) ;
196
203
}
197
204
hir:: PatEnum ( ref path, ref subpats) => {
198
205
let subpats = subpats. as_ref ( ) . map ( |v| & v[ ..] ) ;
199
- check_pat_enum ( pcx, pat, path, subpats, expected) ;
206
+ let is_tuple_struct_pat = !( subpats. is_some ( ) && subpats. unwrap ( ) . is_empty ( ) ) ;
207
+ check_pat_enum ( pcx, pat, path, subpats, expected, is_tuple_struct_pat) ;
200
208
}
201
209
hir:: PatQPath ( ref qself, ref path) => {
202
210
let self_ty = fcx. to_ty ( & qself. ty ) ;
@@ -572,11 +580,19 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx hir::Pat,
572
580
fcx. write_substs ( pat. id , ty:: ItemSubsts { substs : item_substs. clone ( ) } ) ;
573
581
}
574
582
583
+ // This function exists due to the warning "diagnostic code E0164 already used"
584
+ fn bad_struct_kind_err ( sess : & Session , span : Span , path : & hir:: Path , is_warning : bool ) {
585
+ let name = pprust:: path_to_string ( path) ;
586
+ span_err_or_warn ! ( is_warning, sess, span, E0164 ,
587
+ "`{}` does not name a tuple variant or a tuple struct" , name) ;
588
+ }
589
+
575
590
pub fn check_pat_enum < ' a , ' tcx > ( pcx : & pat_ctxt < ' a , ' tcx > ,
576
591
pat : & hir:: Pat ,
577
592
path : & hir:: Path ,
578
593
subpats : Option < & ' tcx [ P < hir:: Pat > ] > ,
579
- expected : Ty < ' tcx > )
594
+ expected : Ty < ' tcx > ,
595
+ is_tuple_struct_pat : bool )
580
596
{
581
597
// Typecheck the path.
582
598
let fcx = pcx. fcx ;
@@ -618,25 +634,52 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
618
634
path_scheme, & ctor_predicates,
619
635
opt_ty, def, pat. span , pat. id ) ;
620
636
637
+ let report_bad_struct_kind = |is_warning| {
638
+ bad_struct_kind_err ( tcx. sess , pat. span , path, is_warning) ;
639
+ fcx. write_error ( pat. id ) ;
640
+
641
+ if let Some ( subpats) = subpats {
642
+ for pat in subpats {
643
+ check_pat ( pcx, & * * pat, tcx. types . err ) ;
644
+ }
645
+ }
646
+ } ;
647
+
621
648
// If we didn't have a fully resolved path to start with, we had an
622
649
// associated const, and we should quit now, since the rest of this
623
650
// function uses checks specific to structs and enums.
624
651
if path_res. depth != 0 {
625
- let pat_ty = fcx. node_ty ( pat. id ) ;
626
- demand:: suptype ( fcx, pat. span , expected, pat_ty) ;
652
+ if is_tuple_struct_pat {
653
+ report_bad_struct_kind ( false ) ;
654
+ } else {
655
+ let pat_ty = fcx. node_ty ( pat. id ) ;
656
+ demand:: suptype ( fcx, pat. span , expected, pat_ty) ;
657
+ }
627
658
return ;
628
659
}
629
660
630
661
let pat_ty = fcx. node_ty ( pat. id ) ;
631
662
demand:: eqtype ( fcx, pat. span , expected, pat_ty) ;
632
663
633
-
634
664
let real_path_ty = fcx. node_ty ( pat. id ) ;
635
665
let ( arg_tys, kind_name) : ( Vec < _ > , & ' static str ) = match real_path_ty. sty {
636
666
ty:: TyEnum ( enum_def, expected_substs)
637
667
if def == def:: DefVariant ( enum_def. did , def. def_id ( ) , false ) =>
638
668
{
639
669
let variant = enum_def. variant_of_def ( def) ;
670
+ if is_tuple_struct_pat && variant. kind ( ) != ty:: VariantKind :: Tuple {
671
+ // Matching unit variants with tuple variant patterns (`UnitVariant(..)`)
672
+ // is allowed for backward compatibility.
673
+ let is_special_case = variant. kind ( ) == ty:: VariantKind :: Unit ;
674
+ report_bad_struct_kind ( is_special_case) ;
675
+ if !is_special_case {
676
+ return
677
+ } else {
678
+ span_note ! ( tcx. sess, pat. span,
679
+ "this warning will become a HARD ERROR in a future release. \
680
+ See RFC 218 for details.") ;
681
+ }
682
+ }
640
683
( variant. fields
641
684
. iter ( )
642
685
. map ( |f| fcx. instantiate_type_scheme ( pat. span ,
@@ -646,26 +689,21 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
646
689
"variant" )
647
690
}
648
691
ty:: TyStruct ( struct_def, expected_substs) => {
649
- ( struct_def. struct_variant ( )
650
- . fields
651
- . iter ( )
652
- . map ( |f| fcx. instantiate_type_scheme ( pat. span ,
653
- expected_substs,
654
- & f. unsubst_ty ( ) ) )
655
- . collect ( ) ,
692
+ let variant = struct_def. struct_variant ( ) ;
693
+ if is_tuple_struct_pat && variant. kind ( ) != ty:: VariantKind :: Tuple {
694
+ report_bad_struct_kind ( false ) ;
695
+ return ;
696
+ }
697
+ ( variant. fields
698
+ . iter ( )
699
+ . map ( |f| fcx. instantiate_type_scheme ( pat. span ,
700
+ expected_substs,
701
+ & f. unsubst_ty ( ) ) )
702
+ . collect ( ) ,
656
703
"struct" )
657
704
}
658
705
_ => {
659
- let name = pprust:: path_to_string ( path) ;
660
- span_err ! ( tcx. sess, pat. span, E0164 ,
661
- "`{}` does not name a non-struct variant or a tuple struct" , name) ;
662
- fcx. write_error ( pat. id ) ;
663
-
664
- if let Some ( subpats) = subpats {
665
- for pat in subpats {
666
- check_pat ( pcx, & * * pat, tcx. types . err ) ;
667
- }
668
- }
706
+ report_bad_struct_kind ( false ) ;
669
707
return ;
670
708
}
671
709
} ;
0 commit comments