Skip to content

Commit ceaec1d

Browse files
committed
check_pat_slice: extract check_aray_pat_len.
Also use `types.err` when matching on `expected.kind`s which don't match `ty::Array(..) | ty::Slice(_)`.
1 parent 13b7101 commit ceaec1d

File tree

1 file changed

+43
-30
lines changed
  • src/librustc_typeck/check

1 file changed

+43
-30
lines changed

src/librustc_typeck/check/pat.rs

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,38 +1174,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11741174
def_bm: BindingMode,
11751175
discrim_span: Option<Span>,
11761176
) -> Ty<'tcx> {
1177-
let tcx = self.tcx;
1177+
let err = self.tcx.types.err;
11781178
let expected = self.structurally_resolved_type(span, expected);
11791179
let (inner_ty, slice_ty, expected) = match expected.kind {
11801180
// An array, so we might have something like `let [a, b, c] = [0, 1, 2];`.
1181-
ty::Array(inner_ty, size) => {
1182-
let slice_ty = if let Some(size) = size.try_eval_usize(tcx, self.param_env) {
1183-
// Now we know the length...
1184-
let min_len = before.len() as u64 + after.len() as u64;
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.
1189-
if min_len != size {
1190-
self.error_scrutinee_inconsistent_length(span, min_len, size)
1191-
}
1192-
tcx.types.err
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...
1196-
tcx.mk_array(inner_ty, rest)
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.
1200-
self.error_scrutinee_with_rest_inconsistent_length(span, min_len, size);
1201-
tcx.types.err
1202-
}
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`.
1206-
self.error_scrutinee_unfixed_length(span);
1207-
tcx.types.err
1208-
};
1181+
ty::Array(inner_ty, len) => {
1182+
let min = before.len() as u64 + after.len() as u64;
1183+
let slice_ty = self.check_array_pat_len(span, slice, len, min)
1184+
.map_or(err, |len| self.tcx.mk_array(inner_ty, len));
12091185
(inner_ty, slice_ty, expected)
12101186
}
12111187
ty::Slice(inner_ty) => (inner_ty, expected, expected),
@@ -1214,7 +1190,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12141190
if !expected.references_error() {
12151191
self.error_expected_array_or_slice(span, expected);
12161192
}
1217-
(tcx.types.err, tcx.types.err, tcx.types.err)
1193+
(err, err, err)
12181194
}
12191195
};
12201196

@@ -1233,6 +1209,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12331209
expected
12341210
}
12351211

1212+
/// Type check the length of an array pattern.
1213+
///
1214+
/// Return the length of the variable length pattern,
1215+
/// if it exists and there are no errors.
1216+
fn check_array_pat_len(
1217+
&self,
1218+
span: Span,
1219+
slice: Option<&'tcx Pat>,
1220+
len: &ty::Const<'tcx>,
1221+
min_len: u64,
1222+
) -> Option<u64> {
1223+
if let Some(len) = len.try_eval_usize(self.tcx, self.param_env) {
1224+
// Now we know the length...
1225+
if slice.is_none() {
1226+
// ...and since there is no variable-length pattern,
1227+
// we require an exact match between the number of elements
1228+
// in the array pattern and as provided by the matched type.
1229+
if min_len != len {
1230+
self.error_scrutinee_inconsistent_length(span, min_len, len);
1231+
}
1232+
} else if let r @ Some(_) = len.checked_sub(min_len) {
1233+
// The variable-length pattern was there,
1234+
// so it has an array type with the remaining elements left as its size...
1235+
return r;
1236+
} else {
1237+
// ...however, in this case, there were no remaining elements.
1238+
// That is, the slice pattern requires more than the array type offers.
1239+
self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len);
1240+
}
1241+
} else {
1242+
// No idea what the length is, which happens if we have e.g.,
1243+
// `let [a, b] = arr` where `arr: [T; N]` where `const N: usize`.
1244+
self.error_scrutinee_unfixed_length(span);
1245+
}
1246+
None
1247+
}
1248+
12361249
fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) {
12371250
struct_span_err!(
12381251
self.tcx.sess,

0 commit comments

Comments
 (0)