about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-12-16 17:33:09 +0100
committerGitHub <noreply@github.com>2019-12-16 17:33:09 +0100
commitf05646ec191d6fe30feacf96a8ff3ceaa43f321c (patch)
tree6f4af4f32bde69e96a0b9bed8c0ebac3d910c21f /src
parenta1580e72daee5fa9b7a61a74a20326b8c5741177 (diff)
parentd9d1f2376f9e2f092e6a01cd14235bdc0c129706 (diff)
downloadrust-f05646ec191d6fe30feacf96a8ff3ceaa43f321c.tar.gz
rust-f05646ec191d6fe30feacf96a8ff3ceaa43f321c.zip
Rollup merge of #67318 - Centril:spdocs, r=matthewjasper
Improve typeck & lowering docs for slice patterns

cc #62254

r? @matthewjasper
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/lowering.rs38
-rw-r--r--src/librustc/hir/mod.rs11
-rw-r--r--src/librustc_typeck/check/mod.rs6
-rw-r--r--src/librustc_typeck/check/pat.rs25
4 files changed, 63 insertions, 17 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index e13f6cabb52..ec9d6802def 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -2852,19 +2852,23 @@ impl<'a> LoweringContext<'a> {
         let mut rest = None;
 
         let mut iter = pats.iter().enumerate();
-        while let Some((idx, pat)) = iter.next() {
-            // Interpret the first `..` pattern as a subtuple pattern.
+        for (idx, pat) in iter.by_ref() {
+            // Interpret the first `..` pattern as a sub-tuple pattern.
+            // Note that unlike for slice patterns,
+            // where `xs @ ..` is a legal sub-slice pattern,
+            // it is not a legal sub-tuple pattern.
             if pat.is_rest() {
                 rest = Some((idx, pat.span));
                 break;
             }
-            // It was not a subslice pattern so lower it normally.
+            // It was not a sub-tuple pattern so lower it normally.
             elems.push(self.lower_pat(pat));
         }
 
-        while let Some((_, pat)) = iter.next() {
-            // There was a previous subtuple pattern; make sure we don't allow more.
+        for (_, pat) in iter {
+            // There was a previous sub-tuple pattern; make sure we don't allow more...
             if pat.is_rest() {
+                // ...but there was one again, so error.
                 self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
             } else {
                 elems.push(self.lower_pat(pat));
@@ -2874,6 +2878,12 @@ impl<'a> LoweringContext<'a> {
         (elems.into(), rest.map(|(ddpos, _)| ddpos))
     }
 
+    /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
+    /// `hir::PatKind::Slice(before, slice, after)`.
+    ///
+    /// When encountering `($binding_mode $ident @)? ..` (`slice`),
+    /// this is interpreted as a sub-slice pattern semantically.
+    /// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
     fn lower_pat_slice(&mut self, pats: &[AstP<Pat>]) -> hir::PatKind {
         let mut before = Vec::new();
         let mut after = Vec::new();
@@ -2881,14 +2891,17 @@ impl<'a> LoweringContext<'a> {
         let mut prev_rest_span = None;
 
         let mut iter = pats.iter();
-        while let Some(pat) = iter.next() {
-            // Interpret the first `((ref mut?)? x @)? ..` pattern as a subslice pattern.
+        // Lower all the patterns until the first occurence of a sub-slice pattern.
+        for pat in iter.by_ref() {
             match pat.kind {
+                // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
                 PatKind::Rest => {
                     prev_rest_span = Some(pat.span);
                     slice = Some(self.pat_wild_with_node_id_of(pat));
                     break;
                 },
+                // Found a sub-slice pattern `$binding_mode $ident @ ..`.
+                // Record, lower it to `$binding_mode $ident @ _`, and stop here.
                 PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
                     prev_rest_span = Some(sub.span);
                     let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
@@ -2896,14 +2909,13 @@ impl<'a> LoweringContext<'a> {
                     slice = Some(self.pat_with_node_id_of(pat, node));
                     break;
                 },
-                _ => {}
+                // It was not a subslice pattern so lower it normally.
+                _ => before.push(self.lower_pat(pat)),
             }
-
-            // It was not a subslice pattern so lower it normally.
-            before.push(self.lower_pat(pat));
         }
 
-        while let Some(pat) = iter.next() {
+        // Lower all the patterns after the first sub-slice pattern.
+        for pat in iter {
             // There was a previous subslice pattern; make sure we don't allow more.
             let rest_span = match pat.kind {
                 PatKind::Rest => Some(pat.span),
@@ -2915,8 +2927,10 @@ impl<'a> LoweringContext<'a> {
                 _ => None,
             };
             if let Some(rest_span) = rest_span {
+                // We have e.g., `[a, .., b, ..]`. That's no good, error!
                 self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
             } else {
+                // Lower the pattern normally.
                 after.push(self.lower_pat(pat));
             }
         }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 66bb3a8d883..6b354b01518 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1048,8 +1048,15 @@ pub enum PatKind {
     /// A range pattern (e.g., `1..=2` or `1..2`).
     Range(P<Expr>, P<Expr>, RangeEnd),
 
-    /// `[a, b, ..i, y, z]` is represented as:
-    ///     `PatKind::Slice(box [a, b], Some(i), box [y, z])`.
+    /// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`.
+    ///
+    /// Here, `slice` is lowered from the syntax `($binding_mode $ident @)? ..`.
+    /// If `slice` exists, then `after` can be non-empty.
+    ///
+    /// The representation for e.g., `[a, b, .., c, d]` is:
+    /// ```
+    /// PatKind::Slice([Binding(a), Binding(b)], Some(Wild), [Binding(c), Binding(d)])
+    /// ```
     Slice(HirVec<P<Pat>>, Option<P<Pat>>, HirVec<P<Pat>>),
 }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 43e7bbcf0c0..65a5405c037 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -5351,9 +5351,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                       directly, not through a function pointer");
     }
 
-    // Resolves `typ` by a single level if `typ` is a type variable.
-    // If no resolution is possible, then an error is reported.
-    // Numeric inference variables may be left unresolved.
+    /// Resolves `typ` by a single level if `typ` is a type variable.
+    /// If no resolution is possible, then an error is reported.
+    /// Numeric inference variables may be left unresolved.
     pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
         let ty = self.resolve_vars_with_obligations(ty);
         if !ty.is_ty_var() {
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);
         }