Skip to content

Commit c1281b4

Browse files
committed
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 rust-lang#38069, to handle uninhabited types. However, in rust-lang#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.
1 parent e6072a7 commit c1281b4

File tree

2 files changed

+46
-9
lines changed

2 files changed

+46
-9
lines changed

src/librustc_const_eval/_match.rs

+18-9
Original file line numberDiff line numberDiff line change
@@ -561,19 +561,25 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
561561
/// (1) all_constructors will only return constructors that are statically
562562
/// possible. eg. it will only return Ok for Result<T, !>
563563
///
564-
/// Whether a vector `v` of patterns is 'useful' in relation to a set of such
565-
/// vectors `m` is defined as there being a set of inputs that will match `v`
566-
/// but not any of the sets in `m`.
564+
/// This finds whether a (row) vector `v` of patterns is 'useful' in relation
565+
/// to a set of such vectors `m` is defined as there being a set of inputs
566+
/// that will match `v` but not any of the sets in `m`.
567+
///
568+
/// All the patterns at each column of the `matrix ++ v` matrix must
569+
/// have the same type, except that wildcard (PatternKind::Wild) patterns
570+
/// with type TyErr are also allowed, even if the "type of the column"
571+
/// is not TyErr. That is used to represent private fields, as using their
572+
/// real type would assert that they are inhabited.
567573
///
568574
/// This is used both for reachability checking (if a pattern isn't useful in
569575
/// relation to preceding patterns, it is not reachable) and exhaustiveness
570576
/// checking (if a wildcard pattern is useful in relation to a matrix, the
571577
/// matrix isn't exhaustive).
572578
pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
573-
matrix: &Matrix<'p, 'tcx>,
574-
v: &[&'p Pattern<'tcx>],
575-
witness: WitnessPreference)
576-
-> Usefulness<'tcx> {
579+
matrix: &Matrix<'p, 'tcx>,
580+
v: &[&'p Pattern<'tcx>],
581+
witness: WitnessPreference)
582+
-> Usefulness<'tcx> {
577583
let &Matrix(ref rows) = matrix;
578584
debug!("is_useful({:?}, {:?})", matrix, v);
579585

@@ -596,6 +602,9 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
596602
assert!(rows.iter().all(|r| r.len() == v.len()));
597603

598604
let pcx = PatternContext {
605+
// () is used to represent an unknown type in this context. If
606+
// one of the fields has a known type, use it instead (other
607+
// than that, all types should be equal modulo normalization).
599608
ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error())
600609
.unwrap_or(v[0].ty),
601610
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>,
861870
if is_visible {
862871
field.ty(cx.tcx, substs)
863872
} else {
864-
// Treat all non-visible fields as nil. They
873+
// Treat all non-visible fields as TyErr. They
865874
// can't appear in any other pattern from
866875
// this match (because they are private),
867876
// so their type does not matter - but
868877
// we don't want to know they are
869878
// uninhabited.
870-
cx.tcx.mk_nil()
879+
cx.tcx.types.err
871880
}
872881
}).collect()
873882
}

src/test/run-pass/issue-46964.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
mod my_mod {
12+
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
13+
pub struct Name<'a> {
14+
source: &'a str,
15+
}
16+
17+
pub const JSON: Name = Name { source: "JSON" };
18+
}
19+
20+
pub fn crash() -> bool {
21+
match (my_mod::JSON, None) {
22+
(_, Some(my_mod::JSON)) => true,
23+
(my_mod::JSON, None) => true,
24+
_ => false,
25+
}
26+
}
27+
28+
fn main() {}

0 commit comments

Comments
 (0)