From c1281b41ecaec037f2e2d7fd75cd0c714dae3f7c Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 25 Dec 2017 18:14:50 +0200 Subject: [PATCH] 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. --- src/librustc_const_eval/_match.rs | 27 ++++++++++++++++++--------- src/test/run-pass/issue-46964.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 src/test/run-pass/issue-46964.rs 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 /// -/// 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 or the MIT license +// , 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() {} -- GitLab