Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

De-abuse TyKind::Error in pattern type checking #70932

Merged
merged 3 commits into from
Apr 10, 2020
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 22 additions & 16 deletions src/librustc_typeck/check/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1353,23 +1353,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
def_bm: BindingMode,
ti: TopInfo<'tcx>,
) -> Ty<'tcx> {
let err = self.tcx.types.err;
let expected = self.structurally_resolved_type(span, expected);
let (element_ty, slice_ty, inferred) = match expected.kind {
let (element_ty, opt_slice_ty, inferred) = match expected.kind {
// An array, so we might have something like `let [a, b, c] = [0, 1, 2];`.
ty::Array(element_ty, len) => {
let min = before.len() as u64 + after.len() as u64;
let (slice_ty, expected) =
let (opt_slice_ty, expected) =
self.check_array_pat_len(span, element_ty, expected, slice, len, min);
(element_ty, slice_ty, expected)
// opt_slice_ty.is_none() => slice.is_none()
mark-i-m marked this conversation as resolved.
Show resolved Hide resolved
// Note, though, that opt_slice_ty could be Some(error_ty).
mark-i-m marked this conversation as resolved.
Show resolved Hide resolved
assert!(opt_slice_ty.is_some() || slice.is_none());
(element_ty, opt_slice_ty, expected)
}
ty::Slice(element_ty) => (element_ty, expected, expected),
ty::Slice(element_ty) => (element_ty, Some(expected), expected),
// The expected type must be an array or slice, but was neither, so error.
_ => {
if !expected.references_error() {
self.error_expected_array_or_slice(span, expected);
}
(err, err, err)
let err = self.tcx.types.err;
(err, Some(err), err)
}
};

Expand All @@ -1379,7 +1382,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// Type check the `slice`, if present, against its expected type.
if let Some(slice) = slice {
self.check_pat(&slice, slice_ty, def_bm, ti);
self.check_pat(&slice, opt_slice_ty.unwrap(), def_bm, ti);
}
// Type check the elements after `slice`, if present.
for elt in after {
Expand All @@ -1390,9 +1393,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

/// Type check the length of an array pattern.
///
/// Returns both the type of the variable length pattern
/// (or `tcx.err` in case there is none),
/// and the potentially inferred array type.
/// Returns both the type of the variable length pattern (or `None`), and the potentially
/// inferred array type. We should only return `None` for the slice type if `slice.is_none()`.
mark-i-m marked this conversation as resolved.
Show resolved Hide resolved
fn check_array_pat_len(
&self,
span: Span,
Expand All @@ -1401,20 +1403,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
slice: Option<&'tcx Pat<'tcx>>,
len: &ty::Const<'tcx>,
min_len: u64,
) -> (Ty<'tcx>, Ty<'tcx>) {
) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
if let Some(len) = len.try_eval_usize(self.tcx, self.param_env) {
// Now we know the length...
if slice.is_none() {
// ...and since there is no variable-length pattern,
// we require an exact match between the number of elements
// in the array pattern and as provided by the matched type.
if min_len != len {
self.error_scrutinee_inconsistent_length(span, min_len, len);
if min_len == len {
return (None, arr_ty);
}

self.error_scrutinee_inconsistent_length(span, min_len, len);
} else if let Some(pat_len) = len.checked_sub(min_len) {
// The variable-length pattern was there,
// so it has an array type with the remaining elements left as its size...
return (self.tcx.mk_array(element_ty, pat_len), arr_ty);
return (Some(self.tcx.mk_array(element_ty, pat_len)), arr_ty);
} else {
// ...however, in this case, there were no remaining elements.
// That is, the slice pattern requires more than the array type offers.
Centril marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -1425,14 +1429,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// which we can use to infer the length of the array.
let updated_arr_ty = self.tcx.mk_array(element_ty, min_len);
self.demand_eqtype(span, updated_arr_ty, arr_ty);
return (self.tcx.types.err, updated_arr_ty);
return (None, updated_arr_ty);
} else {
// We have a variable-length pattern and don't know the array length.
// This happens if we have e.g.,
// `let [a, b, ..] = arr` where `arr: [T; N]` where `const N: usize`.
self.error_scrutinee_unfixed_length(span);
Centril marked this conversation as resolved.
Show resolved Hide resolved
}
(self.tcx.types.err, arr_ty)

// If we get here, we must have emitted an error.
(Some(self.tcx.types.err), arr_ty)
}

fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) {
Expand Down