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.
This commit is contained in:
Ariel Ben-Yehuda 2017-12-25 18:14:50 +02:00
parent e6072a7b38
commit c1281b41ec
2 changed files with 46 additions and 9 deletions

View File

@ -561,9 +561,15 @@ 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
@ -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()
}

View File

@ -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() {}