@@ -1154,6 +1154,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1154
1154
self . tcx . mk_ref ( region, mt)
1155
1155
}
1156
1156
1157
+ /// Type check a slice pattern.
1158
+ ///
1159
+ /// Syntactically, these look like `[pat_0, ..., pat_n]`.
1160
+ /// Semantically, we are type checking a pattern with structure:
1161
+ /// ```
1162
+ /// [before_0, ..., before_n, (slice, after_0, ... after_n)?]
1163
+ /// ```
1164
+ /// The type of `slice`, if it is present, depends on the `expected` type.
1165
+ /// If `slice` is missing, then so is `after_i`.
1166
+ /// If `slice` is present, it can still represent 0 elements.
1157
1167
fn check_pat_slice (
1158
1168
& self ,
1159
1169
span : Span ,
@@ -1167,27 +1177,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1167
1177
let tcx = self . tcx ;
1168
1178
let expected_ty = self . structurally_resolved_type ( span, expected) ;
1169
1179
let ( inner_ty, slice_ty) = match expected_ty. kind {
1180
+ // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`.
1170
1181
ty:: Array ( inner_ty, size) => {
1171
1182
let slice_ty = if let Some ( size) = size. try_eval_usize ( tcx, self . param_env ) {
1183
+ // Now we know the length...
1172
1184
let min_len = before. len ( ) as u64 + after. len ( ) as u64 ;
1173
1185
if slice. is_none ( ) {
1186
+ // ...and since there is no variable-length pattern,
1187
+ // we require an exact match between the number of elements
1188
+ // in the array pattern and as provided by the matched type.
1174
1189
if min_len != size {
1175
1190
self . error_scrutinee_inconsistent_length ( span, min_len, size)
1176
1191
}
1177
1192
tcx. types . err
1178
1193
} else if let Some ( rest) = size. checked_sub ( min_len) {
1194
+ // The variable-length pattern was there,
1195
+ // so it has an array type with the remaining elements left as its size...
1179
1196
tcx. mk_array ( inner_ty, rest)
1180
1197
} else {
1198
+ // ...however, in this case, there were no remaining elements.
1199
+ // That is, the slice pattern requires more than the array type offers.
1181
1200
self . error_scrutinee_with_rest_inconsistent_length ( span, min_len, size) ;
1182
1201
tcx. types . err
1183
1202
}
1184
1203
} else {
1204
+ // No idea what the length is, which happens if we have e.g.,
1205
+ // `let [a, b] = arr` where `arr: [T; N]` where `const N: usize`.
1185
1206
self . error_scrutinee_unfixed_length ( span) ;
1186
1207
tcx. types . err
1187
1208
} ;
1188
1209
( inner_ty, slice_ty)
1189
1210
}
1190
1211
ty:: Slice ( inner_ty) => ( inner_ty, expected_ty) ,
1212
+ // The expected type must be an array or slice, but was neither, so error.
1191
1213
_ => {
1192
1214
if !expected_ty. references_error ( ) {
1193
1215
self . error_expected_array_or_slice ( span, expected_ty) ;
@@ -1196,12 +1218,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1196
1218
}
1197
1219
} ;
1198
1220
1221
+ // Type check all the patterns before `slice`.
1199
1222
for elt in before {
1200
1223
self . check_pat ( & elt, inner_ty, def_bm, discrim_span) ;
1201
1224
}
1225
+ // Type check the `slice`, if present, against its expected type.
1202
1226
if let Some ( slice) = slice {
1203
1227
self . check_pat ( & slice, slice_ty, def_bm, discrim_span) ;
1204
1228
}
1229
+ // Type check the elements after `slice`, if present.
1205
1230
for elt in after {
1206
1231
self . check_pat ( & elt, inner_ty, def_bm, discrim_span) ;
1207
1232
}
0 commit comments