@@ -24,6 +24,7 @@ pub(crate) type PatId = Idx<Pat>;
24
24
pub ( crate ) enum PatternError {
25
25
Unimplemented ,
26
26
UnresolvedVariant ,
27
+ MissingField ,
27
28
}
28
29
29
30
#[ derive( Clone , Debug , PartialEq ) ]
@@ -105,7 +106,7 @@ impl<'a> PatCtxt<'a> {
105
106
}
106
107
107
108
fn lower_pattern_unadjusted ( & mut self , pat : hir_def:: expr:: PatId ) -> Pat {
108
- let ty = & self . infer [ pat] ;
109
+ let mut ty = & self . infer [ pat] ;
109
110
let variant = self . infer . variant_resolution_for_pat ( pat) ;
110
111
111
112
let kind = match self . body [ pat] {
@@ -127,6 +128,9 @@ impl<'a> PatCtxt<'a> {
127
128
}
128
129
129
130
hir_def:: expr:: Pat :: Bind { subpat, .. } => {
131
+ if let TyKind :: Ref ( .., rty) = ty. kind ( & Interner ) {
132
+ ty = rty;
133
+ }
130
134
PatKind :: Binding { subpattern : self . lower_opt_pattern ( subpat) }
131
135
}
132
136
@@ -140,13 +144,21 @@ impl<'a> PatCtxt<'a> {
140
144
let variant_data = variant. unwrap ( ) . variant_data ( self . db . upcast ( ) ) ;
141
145
let subpatterns = args
142
146
. iter ( )
143
- . map ( |field| FieldPat {
147
+ . map ( |field| {
144
148
// XXX(iDawer): field lookup is inefficient
145
- field : variant_data. field ( & field. name ) . unwrap ( ) ,
146
- pattern : self . lower_pattern ( field. pat ) ,
149
+ variant_data. field ( & field. name ) . map ( |lfield_id| FieldPat {
150
+ field : lfield_id,
151
+ pattern : self . lower_pattern ( field. pat ) ,
152
+ } )
147
153
} )
148
154
. collect ( ) ;
149
- self . lower_variant_or_leaf ( pat, ty, subpatterns)
155
+ match subpatterns {
156
+ Some ( subpatterns) => self . lower_variant_or_leaf ( pat, ty, subpatterns) ,
157
+ None => {
158
+ self . errors . push ( PatternError :: MissingField ) ;
159
+ PatKind :: Wild
160
+ }
161
+ }
150
162
}
151
163
hir_def:: expr:: Pat :: TupleStruct { .. } | hir_def:: expr:: Pat :: Record { .. } => {
152
164
self . errors . push ( PatternError :: UnresolvedVariant ) ;
@@ -1090,6 +1102,31 @@ fn main() {
1090
1102
) ;
1091
1103
}
1092
1104
1105
+ #[ test]
1106
+ fn binding_ref_has_correct_type ( ) {
1107
+ // Asserts `PatKind::Binding(ref _x): bool`, not &bool.
1108
+ // If that's not true match checking will panic with "incompatible constructors"
1109
+ // FIXME: make facilities to test this directly like `tests::check_infer(..)`
1110
+ check_diagnostics (
1111
+ r#"
1112
+ enum Foo { A }
1113
+ fn main() {
1114
+ // FIXME: this should not bail out but current behavior is such as the old algorithm.
1115
+ // ExprValidator::validate_match(..) checks types of top level patterns incorrecly.
1116
+ match Foo::A {
1117
+ ref _x => {}
1118
+ // ^^^^^^ Internal: match check bailed out
1119
+ Foo::A => {}
1120
+ }
1121
+ match (true,) {
1122
+ (ref _x,) => {}
1123
+ (true,) => {}
1124
+ }
1125
+ }
1126
+ "# ,
1127
+ ) ;
1128
+ }
1129
+
1093
1130
#[ test]
1094
1131
fn enum_non_exhaustive ( ) {
1095
1132
check_diagnostics (
@@ -1161,6 +1198,19 @@ fn main() {
1161
1198
) ;
1162
1199
}
1163
1200
1201
+ #[ test]
1202
+ fn record_struct_no_such_field ( ) {
1203
+ check_diagnostics (
1204
+ r#"
1205
+ struct Foo { }
1206
+ fn main(f: Foo) {
1207
+ match f { Foo { bar } => () }
1208
+ // ^^^^^^^^^^^ Internal: match check bailed out
1209
+ }
1210
+ "# ,
1211
+ ) ;
1212
+ }
1213
+
1164
1214
mod false_negatives {
1165
1215
//! The implementation of match checking here is a work in progress. As we roll this out, we
1166
1216
//! prefer false negatives to false positives (ideally there would be no false positives). This
0 commit comments