about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2021-09-22 19:29:33 +0100
committerNadrieril <nadrieril+git@gmail.com>2021-09-26 00:05:52 +0100
commit5853399aee2495107659c2de48b18900f17d3d2c (patch)
treede71a044cd0be46a4d03e6e731f8c582f071c67b
parent035c5213aee99adde4895423591e0e076fbb5dd1 (diff)
Move special `&str` handling to `Constructor` and `Fields`
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs20
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs22
2 files changed, 21 insertions, 21 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 46bd29e7a3f..96425381b6b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -660,9 +660,10 @@ impl<'tcx> Constructor<'tcx> {
                 } else {
                     match pat.ty.kind() {
                         ty::Float(_) => FloatRange(value, value, RangeEnd::Included),
-                        // In `expand_pattern`, we convert string literals to `&CONST` patterns with
-                        // `CONST` a pattern of type `str`. In truth this contains a constant of type
-                        // `&str`.
+                        // We make `&str` constants behave like `Deref` patterns, to be compatible
+                        // with other `Deref` patterns. See also `Fields::extract_pattern_arguments`.
+                        ty::Ref(_, t, _) if t.is_str() => Single,
+                        // In truth this carries a constant of type `&str`.
                         ty::Str => Str(value),
                         // All constants that can be structurally matched have already been expanded
                         // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
@@ -1393,6 +1394,19 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
                     self.fields[i] = pat
                 }
             }
+            PatKind::Constant { .. } => match pat.ty.kind() {
+                ty::Ref(_, t, _) if t.is_str() => {
+                    assert_eq!(self.len(), 1);
+                    // We want a `&str` constant to behave like a `Deref` pattern, to be compatible
+                    // with other `Deref` patterns. This could have been done in `const_to_pat`,
+                    // but that causes issues with the rest of the matching code.
+                    // The outer constructor is `&`, and the inner one carries the str value.
+                    let mut new_pat = pat.clone();
+                    new_pat.ty = t; // `t` is `str`, not `&str`
+                    self.fields[0] = &*cx.pattern_arena.alloc(new_pat);
+                }
+                _ => {}
+            },
             _ => {}
         };
         self
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index b518be0141d..76759abca03 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -365,23 +365,9 @@ struct LiteralExpander;
 impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
     fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> {
         debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind);
-        match (pat.ty.kind(), pat.kind.as_ref()) {
-            (_, PatKind::Binding { subpattern: Some(s), .. }) => s.fold_with(self),
-            (_, PatKind::AscribeUserType { subpattern: s, .. }) => s.fold_with(self),
-            (ty::Ref(_, t, _), PatKind::Constant { .. }) if t.is_str() => {
-                // Treat string literal patterns as deref patterns to a `str` constant, i.e.
-                // `&CONST`. This expands them like other const patterns. This could have been done
-                // in `const_to_pat`, but that causes issues with the rest of the matching code.
-                let mut new_pat = pat.super_fold_with(self);
-                // Make a fake const pattern of type `str` (instead of `&str`). That the carried
-                // constant value still knows it is of type `&str`.
-                new_pat.ty = t;
-                Pat {
-                    kind: Box::new(PatKind::Deref { subpattern: new_pat }),
-                    span: pat.span,
-                    ty: pat.ty,
-                }
-            }
+        match pat.kind.as_ref() {
+            PatKind::Binding { subpattern: Some(s), .. } => s.fold_with(self),
+            PatKind::AscribeUserType { subpattern: s, .. } => s.fold_with(self),
             _ => pat.super_fold_with(self),
         }
     }
@@ -1183,7 +1169,7 @@ fn is_useful<'p, 'tcx>(
             let ctor_wild_subpatterns = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
             let spec_matrix =
                 start_matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
-            let v = v.pop_head_constructor(pcx.cx, &ctor_wild_subpatterns);
+            let v = v.pop_head_constructor(cx, &ctor_wild_subpatterns);
             let usefulness =
                 is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false);
             let usefulness =