@@ -49,7 +49,7 @@ pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
49
49
span : DUMMY_SP
50
50
} ;
51
51
52
- struct Matrix < ' a > ( Vec < Vec < & ' a Pat > > ) ;
52
+ struct Matrix < ' a , ' tcx > ( Vec < Vec < ( & ' a Pat , Option < Ty < ' tcx > > ) > > ) ;
53
53
54
54
/// Pretty-printer for matrices of patterns, example:
55
55
/// ++++++++++++++++++++++++++
@@ -63,14 +63,14 @@ struct Matrix<'a>(Vec<Vec<&'a Pat>>);
63
63
/// ++++++++++++++++++++++++++
64
64
/// + _ + [_, _, ..tail] +
65
65
/// ++++++++++++++++++++++++++
66
- impl < ' a > fmt:: Debug for Matrix < ' a > {
66
+ impl < ' a , ' tcx > fmt:: Debug for Matrix < ' a , ' tcx > {
67
67
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
68
68
write ! ( f, "\n " ) ?;
69
69
70
70
let & Matrix ( ref m) = self ;
71
71
let pretty_printed_matrix: Vec < Vec < String > > = m. iter ( ) . map ( |row| {
72
72
row. iter ( )
73
- . map ( |& pat| pat_to_string ( & pat) )
73
+ . map ( |& ( pat, ty ) | format ! ( "{}: {:?}" , pat_to_string( & pat) , ty ) )
74
74
. collect :: < Vec < String > > ( )
75
75
} ) . collect ( ) ;
76
76
@@ -97,8 +97,10 @@ impl<'a> fmt::Debug for Matrix<'a> {
97
97
}
98
98
}
99
99
100
- impl < ' a > FromIterator < Vec < & ' a Pat > > for Matrix < ' a > {
101
- fn from_iter < T : IntoIterator < Item =Vec < & ' a Pat > > > ( iter : T ) -> Matrix < ' a > {
100
+ impl < ' a , ' tcx > FromIterator < Vec < ( & ' a Pat , Option < Ty < ' tcx > > ) > > for Matrix < ' a , ' tcx > {
101
+ fn from_iter < T : IntoIterator < Item =Vec < ( & ' a Pat , Option < Ty < ' tcx > > ) > > > ( iter : T )
102
+ -> Self
103
+ {
102
104
Matrix ( iter. into_iter ( ) . collect ( ) )
103
105
}
104
106
}
@@ -229,7 +231,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
229
231
. iter ( )
230
232
. filter ( |& & ( _, guard) | guard. is_none ( ) )
231
233
. flat_map ( |arm| & arm. 0 )
232
- . map ( |pat| vec ! [ & * * pat] )
234
+ . map ( |pat| vec ! [ wrap_pat ( cx , & pat) ] )
233
235
. collect ( ) ;
234
236
check_exhaustive ( cx, ex. span , & matrix, source) ;
235
237
} ,
@@ -301,7 +303,7 @@ fn check_arms(cx: &MatchCheckCtxt,
301
303
let mut printed_if_let_err = false ;
302
304
for & ( ref pats, guard) in arms {
303
305
for pat in pats {
304
- let v = vec ! [ & * * pat] ;
306
+ let v = vec ! [ wrap_pat ( cx , & pat) ] ;
305
307
306
308
match is_useful ( cx, & seen, & v[ ..] , LeaveOutWitness ) {
307
309
NotUseful => {
@@ -341,8 +343,9 @@ fn check_arms(cx: &MatchCheckCtxt,
341
343
"unreachable pattern" ) ;
342
344
// if we had a catchall pattern, hint at that
343
345
for row in & seen. 0 {
344
- if pat_is_catchall ( & cx. tcx . def_map . borrow ( ) , row[ 0 ] ) {
345
- span_note ! ( err, row[ 0 ] . span, "this pattern matches any value" ) ;
346
+ if pat_is_catchall ( & cx. tcx . def_map . borrow ( ) , row[ 0 ] . 0 ) {
347
+ span_note ! ( err, row[ 0 ] . 0 . span,
348
+ "this pattern matches any value" ) ;
346
349
}
347
350
}
348
351
err. emit ( ) ;
@@ -383,13 +386,16 @@ fn raw_pat(p: &Pat) -> &Pat {
383
386
}
384
387
}
385
388
386
- fn check_exhaustive ( cx : & MatchCheckCtxt , sp : Span , matrix : & Matrix , source : hir:: MatchSource ) {
387
- match is_useful ( cx, matrix, & [ DUMMY_WILD_PAT ] , ConstructWitness ) {
389
+ fn check_exhaustive < ' a , ' tcx > ( cx : & MatchCheckCtxt < ' a , ' tcx > ,
390
+ sp : Span ,
391
+ matrix : & Matrix < ' a , ' tcx > ,
392
+ source : hir:: MatchSource ) {
393
+ match is_useful ( cx, matrix, & [ ( DUMMY_WILD_PAT , None ) ] , ConstructWitness ) {
388
394
UsefulWithWitness ( pats) => {
389
395
let witnesses = if pats. is_empty ( ) {
390
396
vec ! [ DUMMY_WILD_PAT ]
391
397
} else {
392
- pats. iter ( ) . map ( |w| & * * w ) . collect ( )
398
+ pats. iter ( ) . map ( |w| & * * w) . collect ( )
393
399
} ;
394
400
match source {
395
401
hir:: MatchSource :: ForLoopDesugar => {
@@ -631,7 +637,7 @@ impl Constructor {
631
637
fn missing_constructors ( cx : & MatchCheckCtxt , & Matrix ( ref rows) : & Matrix ,
632
638
left_ty : Ty , max_slice_length : usize ) -> Vec < Constructor > {
633
639
let used_constructors: Vec < Constructor > = rows. iter ( )
634
- . flat_map ( |row| pat_constructors ( cx, row[ 0 ] , left_ty, max_slice_length) )
640
+ . flat_map ( |row| pat_constructors ( cx, row[ 0 ] . 0 , left_ty, max_slice_length) )
635
641
. collect ( ) ;
636
642
all_constructors ( cx, left_ty, max_slice_length)
637
643
. into_iter ( )
@@ -668,13 +674,13 @@ fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty,
668
674
669
675
// Note: is_useful doesn't work on empty types, as the paper notes.
670
676
// So it assumes that v is non-empty.
671
- fn is_useful ( cx : & MatchCheckCtxt ,
672
- matrix : & Matrix ,
673
- v : & [ & Pat ] ,
674
- witness : WitnessPreference )
675
- -> Usefulness {
677
+ fn is_useful < ' a , ' tcx > ( cx : & MatchCheckCtxt < ' a , ' tcx > ,
678
+ matrix : & Matrix < ' a , ' tcx > ,
679
+ v : & [ ( & Pat , Option < Ty < ' tcx > > ) ] ,
680
+ witness : WitnessPreference )
681
+ -> Usefulness {
676
682
let & Matrix ( ref rows) = matrix;
677
- debug ! ( "{:?}" , matrix) ;
683
+ debug ! ( "is_useful( {:?}, {:?}) " , matrix, v ) ;
678
684
if rows. is_empty ( ) {
679
685
return match witness {
680
686
ConstructWitness => UsefulWithWitness ( vec ! ( ) ) ,
@@ -685,32 +691,25 @@ fn is_useful(cx: &MatchCheckCtxt,
685
691
return NotUseful ;
686
692
}
687
693
assert ! ( rows. iter( ) . all( |r| r. len( ) == v. len( ) ) ) ;
688
- let real_pat = match rows. iter ( ) . find ( |r| ( * r) [ 0 ] . id != DUMMY_NODE_ID ) {
689
- Some ( r) => raw_pat ( r[ 0 ] ) ,
690
- None if v. is_empty ( ) => return NotUseful ,
691
- None => v[ 0 ]
692
- } ;
693
- let left_ty = if real_pat. id == DUMMY_NODE_ID {
694
- cx. tcx . mk_nil ( )
695
- } else {
696
- let left_ty = cx. tcx . pat_ty ( & real_pat) ;
697
-
698
- match real_pat. node {
699
- PatKind :: Binding ( hir:: BindByRef ( ..) , _, _) => {
700
- left_ty. builtin_deref ( false , NoPreference ) . unwrap ( ) . ty
701
- }
702
- _ => left_ty,
694
+ let left_ty = match rows. iter ( ) . filter_map ( |r| r[ 0 ] . 1 ) . next ( ) . or_else ( || v[ 0 ] . 1 ) {
695
+ Some ( ty) => ty,
696
+ None => {
697
+ // all patterns are wildcards - we can pick any type we want
698
+ cx. tcx . types . bool
703
699
}
704
700
} ;
705
701
706
- let max_slice_length = rows. iter ( ) . filter_map ( |row| match row[ 0 ] . node {
702
+ let max_slice_length = rows. iter ( ) . filter_map ( |row| match row[ 0 ] . 0 . node {
707
703
PatKind :: Vec ( ref before, _, ref after) => Some ( before. len ( ) + after. len ( ) ) ,
708
704
_ => None
709
705
} ) . max ( ) . map_or ( 0 , |v| v + 1 ) ;
710
706
711
- let constructors = pat_constructors ( cx, v[ 0 ] , left_ty, max_slice_length) ;
707
+ let constructors = pat_constructors ( cx, v[ 0 ] . 0 , left_ty, max_slice_length) ;
708
+ debug ! ( "is_useful - pat_constructors = {:?} left_ty = {:?}" , constructors,
709
+ left_ty) ;
712
710
if constructors. is_empty ( ) {
713
711
let constructors = missing_constructors ( cx, matrix, left_ty, max_slice_length) ;
712
+ debug ! ( "is_useful - missing_constructors = {:?}" , constructors) ;
714
713
if constructors. is_empty ( ) {
715
714
all_constructors ( cx, left_ty, max_slice_length) . into_iter ( ) . map ( |c| {
716
715
match is_useful_specialized ( cx, matrix, v, c. clone ( ) , left_ty, witness) {
@@ -731,7 +730,7 @@ fn is_useful(cx: &MatchCheckCtxt,
731
730
} ) . find ( |result| result != & NotUseful ) . unwrap_or ( NotUseful )
732
731
} else {
733
732
let matrix = rows. iter ( ) . filter_map ( |r| {
734
- match raw_pat ( r[ 0 ] ) . node {
733
+ match raw_pat ( r[ 0 ] . 0 ) . node {
735
734
PatKind :: Binding ( ..) | PatKind :: Wild => Some ( r[ 1 ..] . to_vec ( ) ) ,
736
735
_ => None ,
737
736
}
@@ -756,9 +755,14 @@ fn is_useful(cx: &MatchCheckCtxt,
756
755
}
757
756
}
758
757
759
- fn is_useful_specialized ( cx : & MatchCheckCtxt , & Matrix ( ref m) : & Matrix ,
760
- v : & [ & Pat ] , ctor : Constructor , lty : Ty ,
761
- witness : WitnessPreference ) -> Usefulness {
758
+ fn is_useful_specialized < ' a , ' tcx > (
759
+ cx : & MatchCheckCtxt < ' a , ' tcx > ,
760
+ & Matrix ( ref m) : & Matrix < ' a , ' tcx > ,
761
+ v : & [ ( & Pat , Option < Ty < ' tcx > > ) ] ,
762
+ ctor : Constructor ,
763
+ lty : Ty < ' tcx > ,
764
+ witness : WitnessPreference ) -> Usefulness
765
+ {
762
766
let arity = constructor_arity ( cx, & ctor, lty) ;
763
767
let matrix = Matrix ( m. iter ( ) . filter_map ( |r| {
764
768
specialize ( cx, & r[ ..] , & ctor, 0 , arity)
@@ -859,6 +863,19 @@ fn range_covered_by_constructor(ctor: &Constructor,
859
863
}
860
864
}
861
865
866
+ fn wrap_pat < ' a , ' b , ' tcx > ( cx : & MatchCheckCtxt < ' b , ' tcx > ,
867
+ pat : & ' a Pat )
868
+ -> ( & ' a Pat , Option < Ty < ' tcx > > )
869
+ {
870
+ let pat_ty = cx. tcx . pat_ty ( pat) ;
871
+ ( pat, Some ( match pat. node {
872
+ PatKind :: Binding ( hir:: BindByRef ( ..) , _, _) => {
873
+ pat_ty. builtin_deref ( false , NoPreference ) . unwrap ( ) . ty
874
+ }
875
+ _ => pat_ty
876
+ } ) )
877
+ }
878
+
862
879
/// This is the main specialization step. It expands the first pattern in the given row
863
880
/// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
864
881
/// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
@@ -867,14 +884,22 @@ fn range_covered_by_constructor(ctor: &Constructor,
867
884
/// different patterns.
868
885
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
869
886
/// fields filled with wild patterns.
870
- pub fn specialize < ' a > ( cx : & MatchCheckCtxt , r : & [ & ' a Pat ] ,
871
- constructor : & Constructor , col : usize , arity : usize ) -> Option < Vec < & ' a Pat > > {
887
+ pub fn specialize < ' a , ' b , ' tcx > (
888
+ cx : & MatchCheckCtxt < ' b , ' tcx > ,
889
+ r : & [ ( & ' a Pat , Option < Ty < ' tcx > > ) ] ,
890
+ constructor : & Constructor , col : usize , arity : usize )
891
+ -> Option < Vec < ( & ' a Pat , Option < Ty < ' tcx > > ) > >
892
+ {
893
+ let pat = raw_pat ( r[ col] . 0 ) ;
872
894
let & Pat {
873
895
id : pat_id, ref node, span : pat_span
874
- } = raw_pat ( r[ col] ) ;
875
- let head: Option < Vec < & Pat > > = match * node {
896
+ } = pat;
897
+ let wpat = |pat : & ' a Pat | wrap_pat ( cx, pat) ;
898
+ let dummy_pat = ( DUMMY_WILD_PAT , None ) ;
899
+
900
+ let head: Option < Vec < ( & Pat , Option < Ty > ) > > = match * node {
876
901
PatKind :: Binding ( ..) | PatKind :: Wild =>
877
- Some ( vec ! [ DUMMY_WILD_PAT ; arity] ) ,
902
+ Some ( vec ! [ dummy_pat ; arity] ) ,
878
903
879
904
PatKind :: Path ( ..) => {
880
905
let def = cx. tcx . def_map . borrow ( ) . get ( & pat_id) . unwrap ( ) . full_def ( ) ;
@@ -899,12 +924,14 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
899
924
Def :: Variant ( ..) | Def :: Struct ( ..) => {
900
925
match ddpos {
901
926
Some ( ddpos) => {
902
- let mut pats: Vec < _ > = args[ ..ddpos] . iter ( ) . map ( |p| & * * p) . collect ( ) ;
903
- pats. extend ( repeat ( DUMMY_WILD_PAT ) . take ( arity - args. len ( ) ) ) ;
904
- pats. extend ( args[ ddpos..] . iter ( ) . map ( |p| & * * p) ) ;
927
+ let mut pats: Vec < _ > = args[ ..ddpos] . iter ( ) . map ( |p| {
928
+ wpat ( p)
929
+ } ) . collect ( ) ;
930
+ pats. extend ( repeat ( ( DUMMY_WILD_PAT , None ) ) . take ( arity - args. len ( ) ) ) ;
931
+ pats. extend ( args[ ddpos..] . iter ( ) . map ( |p| wpat ( p) ) ) ;
905
932
Some ( pats)
906
933
}
907
- None => Some ( args. iter ( ) . map ( |p| & * * p ) . collect ( ) )
934
+ None => Some ( args. iter ( ) . map ( |p| wpat ( p ) ) . collect ( ) )
908
935
}
909
936
}
910
937
_ => None
@@ -923,8 +950,8 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
923
950
if variant. did == def_variant. did {
924
951
Some ( variant. fields . iter ( ) . map ( |sf| {
925
952
match pattern_fields. iter ( ) . find ( |f| f. node . name == sf. name ) {
926
- Some ( ref f) => & * f. node . pat ,
927
- _ => DUMMY_WILD_PAT
953
+ Some ( ref f) => wpat ( & f. node . pat ) ,
954
+ _ => dummy_pat
928
955
}
929
956
} ) . collect ( ) )
930
957
} else {
@@ -933,25 +960,32 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
933
960
}
934
961
935
962
PatKind :: Tuple ( ref args, Some ( ddpos) ) => {
936
- let mut pats: Vec < _ > = args[ ..ddpos] . iter ( ) . map ( |p| & * * p ) . collect ( ) ;
937
- pats. extend ( repeat ( DUMMY_WILD_PAT ) . take ( arity - args. len ( ) ) ) ;
938
- pats. extend ( args[ ddpos..] . iter ( ) . map ( |p| & * * p ) ) ;
963
+ let mut pats: Vec < _ > = args[ ..ddpos] . iter ( ) . map ( |p| wpat ( p ) ) . collect ( ) ;
964
+ pats. extend ( repeat ( dummy_pat ) . take ( arity - args. len ( ) ) ) ;
965
+ pats. extend ( args[ ddpos..] . iter ( ) . map ( |p| wpat ( p ) ) ) ;
939
966
Some ( pats)
940
967
}
941
968
PatKind :: Tuple ( ref args, None ) =>
942
- Some ( args. iter ( ) . map ( |p| & * * p) . collect ( ) ) ,
969
+ Some ( args. iter ( ) . map ( |p| wpat ( & * * p) ) . collect ( ) ) ,
943
970
944
971
PatKind :: Box ( ref inner) | PatKind :: Ref ( ref inner, _) =>
945
- Some ( vec ! [ & * * inner] ) ,
972
+ Some ( vec ! [ wpat ( & * * inner) ] ) ,
946
973
947
974
PatKind :: Lit ( ref expr) => {
948
- let expr_value = eval_const_expr ( cx. tcx , & expr) ;
949
- match range_covered_by_constructor ( constructor, & expr_value, & expr_value) {
950
- Some ( true ) => Some ( vec ! [ ] ) ,
951
- Some ( false ) => None ,
952
- None => {
953
- span_err ! ( cx. tcx. sess, pat_span, E0298 , "mismatched types between arms" ) ;
954
- None
975
+ if let Some ( & ty:: TyS { sty : ty:: TyRef ( _, mt) , .. } ) = r[ col] . 1 {
976
+ // HACK: handle string literals. A string literal pattern
977
+ // serves both as an unary reference pattern and as a
978
+ // nullary value pattern, depending on the type.
979
+ Some ( vec ! [ ( pat, Some ( mt. ty) ) ] )
980
+ } else {
981
+ let expr_value = eval_const_expr ( cx. tcx , & expr) ;
982
+ match range_covered_by_constructor ( constructor, & expr_value, & expr_value) {
983
+ Some ( true ) => Some ( vec ! [ ] ) ,
984
+ Some ( false ) => None ,
985
+ None => {
986
+ span_err ! ( cx. tcx. sess, pat_span, E0298 , "mismatched types between arms" ) ;
987
+ None
988
+ }
955
989
}
956
990
}
957
991
}
@@ -975,37 +1009,40 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
975
1009
Single => {
976
1010
// Fixed-length vectors.
977
1011
Some (
978
- before. iter ( ) . map ( |p| & * * p ) . chain (
979
- repeat ( DUMMY_WILD_PAT ) . take ( arity - pat_len) . chain (
980
- after. iter ( ) . map ( |p| & * * p )
1012
+ before. iter ( ) . map ( |p| wpat ( p ) ) . chain (
1013
+ repeat ( dummy_pat ) . take ( arity - pat_len) . chain (
1014
+ after. iter ( ) . map ( |p| wpat ( p ) )
981
1015
) ) . collect ( ) )
982
1016
} ,
983
1017
Slice ( length) if pat_len <= length && slice. is_some ( ) => {
984
1018
Some (
985
- before. iter ( ) . map ( |p| & * * p ) . chain (
986
- repeat ( DUMMY_WILD_PAT ) . take ( arity - pat_len) . chain (
987
- after. iter ( ) . map ( |p| & * * p )
1019
+ before. iter ( ) . map ( |p| wpat ( p ) ) . chain (
1020
+ repeat ( dummy_pat ) . take ( arity - pat_len) . chain (
1021
+ after. iter ( ) . map ( |p| wpat ( p ) )
988
1022
) ) . collect ( ) )
989
1023
}
990
1024
Slice ( length) if pat_len == length => {
991
1025
Some (
992
- before. iter ( ) . map ( |p| & * * p ) . chain (
993
- after. iter ( ) . map ( |p| & * * p )
1026
+ before. iter ( ) . map ( |p| wpat ( p ) ) . chain (
1027
+ after. iter ( ) . map ( |p| wpat ( p ) )
994
1028
) . collect ( ) )
995
1029
}
996
1030
SliceWithSubslice ( prefix, suffix)
997
1031
if before. len ( ) == prefix
998
1032
&& after. len ( ) == suffix
999
1033
&& slice. is_some ( ) => {
1000
1034
// this is used by trans::_match only
1001
- let mut pats: Vec < & Pat > = before. iter ( ) . map ( |p| & * * p) . collect ( ) ;
1002
- pats. extend ( after. iter ( ) . map ( |p| & * * p) ) ;
1035
+ let mut pats: Vec < _ > = before. iter ( )
1036
+ . map ( |p| ( & * * p, None ) ) . collect ( ) ;
1037
+ pats. extend ( after. iter ( ) . map ( |p| ( & * * p, None ) ) ) ;
1003
1038
Some ( pats)
1004
1039
}
1005
1040
_ => None
1006
1041
}
1007
1042
}
1008
1043
} ;
1044
+ debug ! ( "specialize({:?}, {:?}) = {:?}" , r[ col] , arity, head) ;
1045
+
1009
1046
head. map ( |mut head| {
1010
1047
head. extend_from_slice ( & r[ ..col] ) ;
1011
1048
head. extend_from_slice ( & r[ col + 1 ..] ) ;
@@ -1063,8 +1100,8 @@ fn check_irrefutable(cx: &MatchCheckCtxt, pat: &Pat, is_fn_arg: bool) {
1063
1100
fn is_refutable < A , F > ( cx : & MatchCheckCtxt , pat : & Pat , refutable : F ) -> Option < A > where
1064
1101
F : FnOnce ( & Pat ) -> A ,
1065
1102
{
1066
- let pats = Matrix ( vec ! ( vec!( pat) ) ) ;
1067
- match is_useful ( cx, & pats, & [ DUMMY_WILD_PAT ] , ConstructWitness ) {
1103
+ let pats = Matrix ( vec ! ( vec!( wrap_pat ( cx , pat) ) ) ) ;
1104
+ match is_useful ( cx, & pats, & [ ( DUMMY_WILD_PAT , None ) ] , ConstructWitness ) {
1068
1105
UsefulWithWitness ( pats) => Some ( refutable ( & pats[ 0 ] ) ) ,
1069
1106
NotUseful => None ,
1070
1107
Useful => bug ! ( )
0 commit comments