about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-02-08 17:13:56 +0000
committerbors <bors@rust-lang.org>2019-02-08 17:13:56 +0000
commita2ec156a5b5d58f2a73bf21b1fe037b6ac1cf5cc (patch)
tree29a60d54848218c387047656d2529aee28f97ca3
parent0710c2026f257b9560f7f84539bc57183c3a02d3 (diff)
parent6717727fcbc8e07f471b4a6d8fecd600230a5616 (diff)
downloadrust-a2ec156a5b5d58f2a73bf21b1fe037b6ac1cf5cc.tar.gz
rust-a2ec156a5b5d58f2a73bf21b1fe037b6ac1cf5cc.zip
Auto merge of #58161 - davidtwco:issue-57960, r=arielb1
Lower constant patterns with ascribed types.

Fixes #57960.

This PR fixes a bug introduced by #55937 which started checking user
type annotations for associated type patterns. Where lowering a
associated constant expression would previously return a
`PatternKind::Constant`, it now returns a `PatternKind::AscribeUserType`
with a `PatternKind::Constant` inside, this PR unwraps that to
access the constant pattern inside and behaves as before.

r? @pnkfelix
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs33
-rw-r--r--src/test/ui/nll/issue-57960.rs39
2 files changed, 68 insertions, 4 deletions
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 6b7e1416118..eacb11fc1ac 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -167,6 +167,17 @@ pub enum PatternKind<'tcx> {
     },
 }
 
+impl<'tcx> PatternKind<'tcx> {
+    /// If this is a `PatternKind::AscribeUserType` then return the subpattern kind, otherwise
+    /// return this pattern kind.
+    fn with_user_type_ascription_subpattern(self) -> Self {
+        match self {
+            PatternKind::AscribeUserType { subpattern: Pattern { box kind, ..  }, ..  } => kind,
+            kind => kind,
+        }
+    }
+}
+
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub struct PatternRange<'tcx> {
     pub lo: ty::Const<'tcx>,
@@ -403,9 +414,15 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
             PatKind::Lit(ref value) => self.lower_lit(value),
 
             PatKind::Range(ref lo_expr, ref hi_expr, end) => {
-                match (self.lower_lit(lo_expr), self.lower_lit(hi_expr)) {
-                    (PatternKind::Constant { value: lo },
-                     PatternKind::Constant { value: hi }) => {
+                match (
+                    // Look for `PatternKind::Constant` patterns inside of any
+                    // `PatternKind::AscribeUserType` patterns. Type ascriptions can be safely
+                    // ignored for the purposes of lowering a range correctly - these are checked
+                    // elsewhere for well-formedness.
+                    self.lower_lit(lo_expr).with_user_type_ascription_subpattern(),
+                    self.lower_lit(hi_expr).with_user_type_ascription_subpattern(),
+                ) {
+                    (PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => {
                         use std::cmp::Ordering;
                         let cmp = compare_const_vals(
                             self.tcx,
@@ -454,7 +471,15 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                             }
                         }
                     }
-                    _ => PatternKind::Wild
+                    ref pats => {
+                        self.tcx.sess.delay_span_bug(
+                            pat.span,
+                            &format!("found bad range pattern `{:?}` outside of error recovery",
+                                     pats),
+                        );
+
+                        PatternKind::Wild
+                    }
                 }
             }
 
diff --git a/src/test/ui/nll/issue-57960.rs b/src/test/ui/nll/issue-57960.rs
new file mode 100644
index 00000000000..0b52e46c459
--- /dev/null
+++ b/src/test/ui/nll/issue-57960.rs
@@ -0,0 +1,39 @@
+// run-pass
+
+#![allow(dead_code)]
+
+trait Range {
+    const FIRST: u8;
+    const LAST: u8;
+}
+
+struct OneDigit;
+impl Range for OneDigit {
+    const FIRST: u8 = 0;
+    const LAST: u8 = 9;
+}
+
+struct TwoDigits;
+impl Range for TwoDigits {
+    const FIRST: u8 = 10;
+    const LAST: u8 = 99;
+}
+
+struct ThreeDigits;
+impl Range for ThreeDigits {
+    const FIRST: u8 = 100;
+    const LAST: u8 = 255;
+}
+
+fn digits(x: u8) -> u32 {
+    match x {
+        OneDigit::FIRST...OneDigit::LAST => 1,
+        TwoDigits::FIRST...TwoDigits::LAST => 2,
+        ThreeDigits::FIRST...ThreeDigits::LAST => 3,
+        _ => unreachable!(),
+    }
+}
+
+fn main() {
+    assert_eq!(digits(100), 3);
+}