about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-12-25 18:14:50 +0200
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2018-01-13 21:17:19 +0200
commitc1281b41ecaec037f2e2d7fd75cd0c714dae3f7c (patch)
tree787fb1247f6d77bb90ac793e3d256c12a97992b3 /src
parente6072a7b3835f1875e81c9fd27799f9b20a0770c (diff)
downloadrust-c1281b41ecaec037f2e2d7fd75cd0c714dae3f7c.tar.gz
rust-c1281b41ecaec037f2e2d7fd75cd0c714dae3f7c.zip
check_match: fix handling of privately uninhabited types
the match-checking code used to use TyErr for signaling "unknown,
inhabited" types for a long time. It had been switched to using the
exact type in #38069, to handle uninhabited types.

However, in #39980, we discovered that we still needed the "unknown
inhabited" logic, but I used `()` instead of `TyErr` to handle that.
Revert to using `TyErr` to fix that problem.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_const_eval/_match.rs27
-rw-r--r--src/test/run-pass/issue-46964.rs28
2 files changed, 46 insertions, 9 deletions
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index 33d9bfa6e6b..e52ea26bf81 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -561,19 +561,25 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
 ///   (1) all_constructors will only return constructors that are statically
 ///       possible. eg. it will only return Ok for Result<T, !>
 ///
-/// Whether a vector `v` of patterns is 'useful' in relation to a set of such
-/// vectors `m` is defined as there being a set of inputs that will match `v`
-/// but not any of the sets in `m`.
+/// This finds whether a (row) vector `v` of patterns is 'useful' in relation
+/// to a set of such vectors `m` is defined as there being a set of inputs
+/// that will match `v` but not any of the sets in `m`.
+///
+/// All the patterns at each column of the `matrix ++ v` matrix must
+/// have the same type, except that wildcard (PatternKind::Wild) patterns
+/// with type TyErr are also allowed, even if the "type of the column"
+/// is not TyErr. That is used to represent private fields, as using their
+/// real type would assert that they are inhabited.
 ///
 /// This is used both for reachability checking (if a pattern isn't useful in
 /// relation to preceding patterns, it is not reachable) and exhaustiveness
 /// checking (if a wildcard pattern is useful in relation to a matrix, the
 /// matrix isn't exhaustive).
 pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
-                           matrix: &Matrix<'p, 'tcx>,
-                           v: &[&'p Pattern<'tcx>],
-                           witness: WitnessPreference)
-                           -> Usefulness<'tcx> {
+                                       matrix: &Matrix<'p, 'tcx>,
+                                       v: &[&'p Pattern<'tcx>],
+                                       witness: WitnessPreference)
+                                       -> Usefulness<'tcx> {
     let &Matrix(ref rows) = matrix;
     debug!("is_useful({:?}, {:?})", matrix, v);
 
@@ -596,6 +602,9 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
     assert!(rows.iter().all(|r| r.len() == v.len()));
 
     let pcx = PatternContext {
+        // () is used to represent an unknown type in this context. If
+        // one of the fields has a known type, use it instead (other
+        // than that, all types should be equal modulo normalization).
         ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error())
             .unwrap_or(v[0].ty),
         max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0])))
@@ -861,13 +870,13 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
                     if is_visible {
                         field.ty(cx.tcx, substs)
                     } else {
-                        // Treat all non-visible fields as nil. They
+                        // Treat all non-visible fields as TyErr. They
                         // can't appear in any other pattern from
                         // this match (because they are private),
                         // so their type does not matter - but
                         // we don't want to know they are
                         // uninhabited.
-                        cx.tcx.mk_nil()
+                        cx.tcx.types.err
                     }
                 }).collect()
             }
diff --git a/src/test/run-pass/issue-46964.rs b/src/test/run-pass/issue-46964.rs
new file mode 100644
index 00000000000..2a82c6dd438
--- /dev/null
+++ b/src/test/run-pass/issue-46964.rs
@@ -0,0 +1,28 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod my_mod {
+    #[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
+    pub struct Name<'a> {
+        source: &'a str,
+    }
+
+    pub const JSON: Name = Name { source: "JSON" };
+}
+
+pub fn crash() -> bool {
+  match (my_mod::JSON, None) {
+    (_, Some(my_mod::JSON)) => true,
+    (my_mod::JSON, None) => true,
+    _ => false,
+  }
+}
+
+fn main() {}