Skip to content

Commit f05646e

Browse files
authored
Rollup merge of rust-lang#67318 - Centril:spdocs, r=matthewjasper
Improve typeck & lowering docs for slice patterns cc rust-lang#62254 r? @matthewjasper
2 parents a1580e7 + d9d1f23 commit f05646e

File tree

4 files changed

+63
-17
lines changed

4 files changed

+63
-17
lines changed

Diff for: src/librustc/hir/lowering.rs

+26-12
Original file line numberDiff line numberDiff line change
@@ -2852,19 +2852,23 @@ impl<'a> LoweringContext<'a> {
28522852
let mut rest = None;
28532853

28542854
let mut iter = pats.iter().enumerate();
2855-
while let Some((idx, pat)) = iter.next() {
2856-
// Interpret the first `..` pattern as a subtuple pattern.
2855+
for (idx, pat) in iter.by_ref() {
2856+
// Interpret the first `..` pattern as a sub-tuple pattern.
2857+
// Note that unlike for slice patterns,
2858+
// where `xs @ ..` is a legal sub-slice pattern,
2859+
// it is not a legal sub-tuple pattern.
28572860
if pat.is_rest() {
28582861
rest = Some((idx, pat.span));
28592862
break;
28602863
}
2861-
// It was not a subslice pattern so lower it normally.
2864+
// It was not a sub-tuple pattern so lower it normally.
28622865
elems.push(self.lower_pat(pat));
28632866
}
28642867

2865-
while let Some((_, pat)) = iter.next() {
2866-
// There was a previous subtuple pattern; make sure we don't allow more.
2868+
for (_, pat) in iter {
2869+
// There was a previous sub-tuple pattern; make sure we don't allow more...
28672870
if pat.is_rest() {
2871+
// ...but there was one again, so error.
28682872
self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
28692873
} else {
28702874
elems.push(self.lower_pat(pat));
@@ -2874,36 +2878,44 @@ impl<'a> LoweringContext<'a> {
28742878
(elems.into(), rest.map(|(ddpos, _)| ddpos))
28752879
}
28762880

2881+
/// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
2882+
/// `hir::PatKind::Slice(before, slice, after)`.
2883+
///
2884+
/// When encountering `($binding_mode $ident @)? ..` (`slice`),
2885+
/// this is interpreted as a sub-slice pattern semantically.
2886+
/// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
28772887
fn lower_pat_slice(&mut self, pats: &[AstP<Pat>]) -> hir::PatKind {
28782888
let mut before = Vec::new();
28792889
let mut after = Vec::new();
28802890
let mut slice = None;
28812891
let mut prev_rest_span = None;
28822892

28832893
let mut iter = pats.iter();
2884-
while let Some(pat) = iter.next() {
2885-
// Interpret the first `((ref mut?)? x @)? ..` pattern as a subslice pattern.
2894+
// Lower all the patterns until the first occurence of a sub-slice pattern.
2895+
for pat in iter.by_ref() {
28862896
match pat.kind {
2897+
// Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
28872898
PatKind::Rest => {
28882899
prev_rest_span = Some(pat.span);
28892900
slice = Some(self.pat_wild_with_node_id_of(pat));
28902901
break;
28912902
},
2903+
// Found a sub-slice pattern `$binding_mode $ident @ ..`.
2904+
// Record, lower it to `$binding_mode $ident @ _`, and stop here.
28922905
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
28932906
prev_rest_span = Some(sub.span);
28942907
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
28952908
let node = self.lower_pat_ident(pat, bm, ident, lower_sub);
28962909
slice = Some(self.pat_with_node_id_of(pat, node));
28972910
break;
28982911
},
2899-
_ => {}
2912+
// It was not a subslice pattern so lower it normally.
2913+
_ => before.push(self.lower_pat(pat)),
29002914
}
2901-
2902-
// It was not a subslice pattern so lower it normally.
2903-
before.push(self.lower_pat(pat));
29042915
}
29052916

2906-
while let Some(pat) = iter.next() {
2917+
// Lower all the patterns after the first sub-slice pattern.
2918+
for pat in iter {
29072919
// There was a previous subslice pattern; make sure we don't allow more.
29082920
let rest_span = match pat.kind {
29092921
PatKind::Rest => Some(pat.span),
@@ -2915,8 +2927,10 @@ impl<'a> LoweringContext<'a> {
29152927
_ => None,
29162928
};
29172929
if let Some(rest_span) = rest_span {
2930+
// We have e.g., `[a, .., b, ..]`. That's no good, error!
29182931
self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
29192932
} else {
2933+
// Lower the pattern normally.
29202934
after.push(self.lower_pat(pat));
29212935
}
29222936
}

Diff for: src/librustc/hir/mod.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1048,8 +1048,15 @@ pub enum PatKind {
10481048
/// A range pattern (e.g., `1..=2` or `1..2`).
10491049
Range(P<Expr>, P<Expr>, RangeEnd),
10501050

1051-
/// `[a, b, ..i, y, z]` is represented as:
1052-
/// `PatKind::Slice(box [a, b], Some(i), box [y, z])`.
1051+
/// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`.
1052+
///
1053+
/// Here, `slice` is lowered from the syntax `($binding_mode $ident @)? ..`.
1054+
/// If `slice` exists, then `after` can be non-empty.
1055+
///
1056+
/// The representation for e.g., `[a, b, .., c, d]` is:
1057+
/// ```
1058+
/// PatKind::Slice([Binding(a), Binding(b)], Some(Wild), [Binding(c), Binding(d)])
1059+
/// ```
10531060
Slice(HirVec<P<Pat>>, Option<P<Pat>>, HirVec<P<Pat>>),
10541061
}
10551062

Diff for: src/librustc_typeck/check/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5351,9 +5351,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
53515351
directly, not through a function pointer");
53525352
}
53535353

5354-
// Resolves `typ` by a single level if `typ` is a type variable.
5355-
// If no resolution is possible, then an error is reported.
5356-
// Numeric inference variables may be left unresolved.
5354+
/// Resolves `typ` by a single level if `typ` is a type variable.
5355+
/// If no resolution is possible, then an error is reported.
5356+
/// Numeric inference variables may be left unresolved.
53575357
pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
53585358
let ty = self.resolve_vars_with_obligations(ty);
53595359
if !ty.is_ty_var() {

Diff for: src/librustc_typeck/check/pat.rs

+25
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11541154
self.tcx.mk_ref(region, mt)
11551155
}
11561156

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.
11571167
fn check_pat_slice(
11581168
&self,
11591169
span: Span,
@@ -1167,27 +1177,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11671177
let tcx = self.tcx;
11681178
let expected_ty = self.structurally_resolved_type(span, expected);
11691179
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];`.
11701181
ty::Array(inner_ty, size) => {
11711182
let slice_ty = if let Some(size) = size.try_eval_usize(tcx, self.param_env) {
1183+
// Now we know the length...
11721184
let min_len = before.len() as u64 + after.len() as u64;
11731185
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.
11741189
if min_len != size {
11751190
self.error_scrutinee_inconsistent_length(span, min_len, size)
11761191
}
11771192
tcx.types.err
11781193
} 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...
11791196
tcx.mk_array(inner_ty, rest)
11801197
} else {
1198+
// ...however, in this case, there were no remaining elements.
1199+
// That is, the slice pattern requires more than the array type offers.
11811200
self.error_scrutinee_with_rest_inconsistent_length(span, min_len, size);
11821201
tcx.types.err
11831202
}
11841203
} 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`.
11851206
self.error_scrutinee_unfixed_length(span);
11861207
tcx.types.err
11871208
};
11881209
(inner_ty, slice_ty)
11891210
}
11901211
ty::Slice(inner_ty) => (inner_ty, expected_ty),
1212+
// The expected type must be an array or slice, but was neither, so error.
11911213
_ => {
11921214
if !expected_ty.references_error() {
11931215
self.error_expected_array_or_slice(span, expected_ty);
@@ -1196,12 +1218,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11961218
}
11971219
};
11981220

1221+
// Type check all the patterns before `slice`.
11991222
for elt in before {
12001223
self.check_pat(&elt, inner_ty, def_bm, discrim_span);
12011224
}
1225+
// Type check the `slice`, if present, against its expected type.
12021226
if let Some(slice) = slice {
12031227
self.check_pat(&slice, slice_ty, def_bm, discrim_span);
12041228
}
1229+
// Type check the elements after `slice`, if present.
12051230
for elt in after {
12061231
self.check_pat(&elt, inner_ty, def_bm, discrim_span);
12071232
}

0 commit comments

Comments
 (0)