diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-12-15 13:16:01 +0100 |
|---|---|---|
| committer | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-12-15 13:16:01 +0100 |
| commit | d848ce0ddf4f20bd6fbae70ad126640247f61a56 (patch) | |
| tree | 49ea3981727a7efa7d63e36123db94023c886670 | |
| parent | f2d6413eb276caa4d881da1aad759b02a64c6aea (diff) | |
| download | rust-d848ce0ddf4f20bd6fbae70ad126640247f61a56.tar.gz rust-d848ce0ddf4f20bd6fbae70ad126640247f61a56.zip | |
document check_pat_slice
| -rw-r--r-- | src/librustc_typeck/check/pat.rs | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 71d1cd869a6..4fb57a65625 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -1154,6 +1154,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.mk_ref(region, mt) } + /// Type check a slice pattern. + /// + /// Syntactically, these look like `[pat_0, ..., pat_n]`. + /// Semantically, we are type checking a pattern with structure: + /// ``` + /// [before_0, ..., before_n, (slice, after_0, ... after_n)?] + /// ``` + /// The type of `slice`, if it is present, depends on the `expected` type. + /// If `slice` is missing, then so is `after_i`. + /// If `slice` is present, it can still represent 0 elements. fn check_pat_slice( &self, span: Span, @@ -1167,27 +1177,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; let expected_ty = self.structurally_resolved_type(span, expected); let (inner_ty, slice_ty) = match expected_ty.kind { + // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`. ty::Array(inner_ty, size) => { let slice_ty = if let Some(size) = size.try_eval_usize(tcx, self.param_env) { + // Now we know the length... let min_len = before.len() as u64 + after.len() as u64; 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 != size { self.error_scrutinee_inconsistent_length(span, min_len, size) } tcx.types.err } else if let Some(rest) = size.checked_sub(min_len) { + // The variable-length pattern was there, + // so it has an array type with the remaining elements left as its size... tcx.mk_array(inner_ty, rest) } else { + // ...however, in this case, there were no remaining elements. + // That is, the slice pattern requires more than the array type offers. self.error_scrutinee_with_rest_inconsistent_length(span, min_len, size); tcx.types.err } } else { + // No idea what the length is, which happens if we have e.g., + // `let [a, b] = arr` where `arr: [T; N]` where `const N: usize`. self.error_scrutinee_unfixed_length(span); tcx.types.err }; (inner_ty, slice_ty) } ty::Slice(inner_ty) => (inner_ty, expected_ty), + // The expected type must be an array or slice, but was neither, so error. _ => { if !expected_ty.references_error() { self.error_expected_array_or_slice(span, expected_ty); @@ -1196,12 +1218,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; + // Type check all the patterns before `slice`. for elt in before { self.check_pat(&elt, inner_ty, def_bm, discrim_span); } + // Type check the `slice`, if present, against its expected type. if let Some(slice) = slice { self.check_pat(&slice, slice_ty, def_bm, discrim_span); } + // Type check the elements after `slice`, if present. for elt in after { self.check_pat(&elt, inner_ty, def_bm, discrim_span); } |
