mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
More pattern matching for empty types changes
Fix is_uninhabited for enum types. It used to assume that an enums variant's fields were all private. Fix MIR generation for irrefutable Variant pattern matches. This allows code like this to work: let x: Result<32, !> = Ok(123); let Ok(y) = x; Carry type information on dummy wildcard patterns. Sometimes we need to expand these patterns into their constructors and we don't want to be expanding a TyError into a Constructor::Single.
This commit is contained in:
parent
bcdbe942e1
commit
9c5e86d0cd
@ -888,6 +888,10 @@ impl<'tcx> Lvalue<'tcx> {
|
||||
self.elem(ProjectionElem::Deref)
|
||||
}
|
||||
|
||||
pub fn downcast(self, adt_def: AdtDef<'tcx>, variant_index: usize) -> Lvalue<'tcx> {
|
||||
self.elem(ProjectionElem::Downcast(adt_def, variant_index))
|
||||
}
|
||||
|
||||
pub fn index(self, index: Operand<'tcx>) -> Lvalue<'tcx> {
|
||||
self.elem(ProjectionElem::Index(index))
|
||||
}
|
||||
|
@ -1416,7 +1416,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
return false;
|
||||
};
|
||||
self.variants.iter().all(|v| {
|
||||
v.is_uninhabited_recurse(visited, block, tcx, substs, self.is_union())
|
||||
v.is_uninhabited_recurse(visited, block, tcx, substs, self.adt_kind())
|
||||
})
|
||||
}
|
||||
|
||||
@ -1761,11 +1761,23 @@ impl<'a, 'gcx, 'tcx> VariantDef {
|
||||
block: Option<NodeId>,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
is_union: bool) -> bool {
|
||||
if is_union {
|
||||
self.fields.iter().all(|f| f.is_uninhabited_recurse(visited, block, tcx, substs))
|
||||
} else {
|
||||
self.fields.iter().any(|f| f.is_uninhabited_recurse(visited, block, tcx, substs))
|
||||
adt_kind: AdtKind) -> bool {
|
||||
match adt_kind {
|
||||
AdtKind::Union => {
|
||||
self.fields.iter().all(|f| {
|
||||
f.is_uninhabited_recurse(visited, block, tcx, substs, false)
|
||||
})
|
||||
},
|
||||
AdtKind::Struct => {
|
||||
self.fields.iter().any(|f| {
|
||||
f.is_uninhabited_recurse(visited, block, tcx, substs, false)
|
||||
})
|
||||
},
|
||||
AdtKind::Enum => {
|
||||
self.fields.iter().any(|f| {
|
||||
f.is_uninhabited_recurse(visited, block, tcx, substs, true)
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1780,9 +1792,12 @@ impl<'a, 'gcx, 'tcx> FieldDef {
|
||||
visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
|
||||
block: Option<NodeId>,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
substs: &'tcx Substs<'tcx>) -> bool {
|
||||
block.map_or(true, |b| tcx.vis_is_accessible_from(self.vis, b)) &&
|
||||
self.ty(tcx, substs).is_uninhabited_recurse(visited, block, tcx)
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
is_enum: bool) -> bool {
|
||||
let visible = is_enum || block.map_or(true, |b| {
|
||||
tcx.vis_is_accessible_from(self.vis, b)
|
||||
});
|
||||
visible && self.ty(tcx, substs).is_uninhabited_recurse(visited, block, tcx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ use pattern::{FieldPattern, Pattern, PatternKind};
|
||||
use pattern::{PatternFoldable, PatternFolder};
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
|
||||
|
||||
use rustc::mir::Field;
|
||||
use rustc::util::common::ErrorReported;
|
||||
@ -153,9 +153,6 @@ pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
|
||||
/// can not be seen to be empty outside it's module and should not
|
||||
/// be matchable with an empty match statement.
|
||||
pub node: NodeId,
|
||||
/// A wild pattern with an error type - it exists to avoid having to normalize
|
||||
/// associated types to get field types.
|
||||
pub wild_pattern: &'a Pattern<'tcx>,
|
||||
pub pattern_arena: &'a TypedArena<Pattern<'tcx>>,
|
||||
pub byte_array_map: FxHashMap<*const Pattern<'tcx>, Vec<&'a Pattern<'tcx>>>,
|
||||
}
|
||||
@ -167,25 +164,20 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
|
||||
f: F) -> R
|
||||
where F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R
|
||||
{
|
||||
let wild_pattern = Pattern {
|
||||
ty: tcx.types.err,
|
||||
span: DUMMY_SP,
|
||||
kind: box PatternKind::Wild
|
||||
};
|
||||
|
||||
let pattern_arena = TypedArena::new();
|
||||
|
||||
f(MatchCheckCtxt {
|
||||
tcx: tcx,
|
||||
node: node,
|
||||
wild_pattern: &wild_pattern,
|
||||
pattern_arena: &pattern_arena,
|
||||
byte_array_map: FxHashMap(),
|
||||
})
|
||||
}
|
||||
|
||||
// convert a byte-string pattern to a list of u8 patterns.
|
||||
fn lower_byte_str_pattern(&mut self, pat: &'a Pattern<'tcx>) -> Vec<&'a Pattern<'tcx>> {
|
||||
fn lower_byte_str_pattern<'p>(&mut self, pat: &'p Pattern<'tcx>) -> Vec<&'p Pattern<'tcx>>
|
||||
where 'a: 'p
|
||||
{
|
||||
let pattern_arena = &*self.pattern_arena;
|
||||
let tcx = self.tcx;
|
||||
self.byte_array_map.entry(pat).or_insert_with(|| {
|
||||
@ -401,6 +393,7 @@ fn missing_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
pcx: PatternContext<'tcx>) -> Vec<Constructor>
|
||||
{
|
||||
debug!("all_constructors({:?})", pcx.ty);
|
||||
match pcx.ty.sty {
|
||||
ty::TyBool =>
|
||||
[true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
|
||||
@ -421,7 +414,10 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => {
|
||||
def.variants.iter().filter_map(|v| {
|
||||
let mut visited = FxHashSet::default();
|
||||
if v.is_uninhabited_recurse(&mut visited, Some(cx.node), cx.tcx, substs, false) {
|
||||
if v.is_uninhabited_recurse(&mut visited,
|
||||
Some(cx.node),
|
||||
cx.tcx, substs,
|
||||
AdtKind::Enum) {
|
||||
None
|
||||
} else {
|
||||
Some(Variant(v.did))
|
||||
@ -438,10 +434,10 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
fn max_slice_length<'a, 'tcx, I>(
|
||||
fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
|
||||
_cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
patterns: I) -> usize
|
||||
where I: Iterator<Item=&'a Pattern<'tcx>>
|
||||
where I: Iterator<Item=&'p Pattern<'tcx>>
|
||||
{
|
||||
// The exhaustiveness-checking paper does not include any details on
|
||||
// checking variable-length slice patterns. However, they are matched
|
||||
@ -532,6 +528,12 @@ fn max_slice_length<'a, 'tcx, I>(
|
||||
}
|
||||
|
||||
/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
|
||||
/// The algorithm from the paper has been modified to correctly handle empty
|
||||
/// types. The changes are:
|
||||
/// (0) We don't exit early if the pattern matrix has zero rows. We just
|
||||
/// continue to recurse over columns.
|
||||
/// (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`
|
||||
@ -541,12 +543,9 @@ fn max_slice_length<'a, 'tcx, I>(
|
||||
/// 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).
|
||||
///
|
||||
/// Note: is_useful doesn't work on empty types, as the paper notes.
|
||||
/// So it assumes that v is non-empty.
|
||||
pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
matrix: &Matrix<'a, 'tcx>,
|
||||
v: &[&'a Pattern<'tcx>],
|
||||
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> {
|
||||
let &Matrix(ref rows) = matrix;
|
||||
@ -616,19 +615,27 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_useful_specialized<'a, 'tcx>(
|
||||
fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
|
||||
cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
&Matrix(ref m): &Matrix<'a, 'tcx>,
|
||||
v: &[&'a Pattern<'tcx>],
|
||||
&Matrix(ref m): &Matrix<'p, 'tcx>,
|
||||
v: &[&'p Pattern<'tcx>],
|
||||
ctor: Constructor,
|
||||
lty: Ty<'tcx>,
|
||||
witness: WitnessPreference) -> Usefulness<'tcx>
|
||||
{
|
||||
let arity = constructor_arity(cx, &ctor, lty);
|
||||
let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty);
|
||||
let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| {
|
||||
Pattern {
|
||||
ty: ty,
|
||||
span: DUMMY_SP,
|
||||
kind: box PatternKind::Wild,
|
||||
}
|
||||
}).collect();
|
||||
let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect();
|
||||
let matrix = Matrix(m.iter().flat_map(|r| {
|
||||
specialize(cx, &r[..], &ctor, 0, arity)
|
||||
specialize(cx, &r[..], &ctor, &wild_patterns)
|
||||
}).collect());
|
||||
match specialize(cx, v, &ctor, 0, arity) {
|
||||
match specialize(cx, v, &ctor, &wild_patterns) {
|
||||
Some(v) => match is_useful(cx, &matrix, &v[..], witness) {
|
||||
UsefulWithWitness(witnesses) => UsefulWithWitness(
|
||||
witnesses.into_iter()
|
||||
@ -703,6 +710,33 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize
|
||||
}
|
||||
}
|
||||
|
||||
/// This computes the types of the sub patterns that a constructor should be
|
||||
/// expanded to.
|
||||
///
|
||||
/// For instance, a tuple pattern (43u32, 'a') has sub pattern types [u32, char].
|
||||
fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
ctor: &Constructor,
|
||||
ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
|
||||
{
|
||||
debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty);
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref fs) => fs.into_iter().map(|t| *t).collect(),
|
||||
ty::TyBox(ty) => vec![ty],
|
||||
ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor {
|
||||
Slice(length) => repeat(ty).take(length).collect(),
|
||||
ConstantValue(_) => vec![],
|
||||
_ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
|
||||
},
|
||||
ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty],
|
||||
ty::TyAdt(adt, substs) => {
|
||||
ctor.variant_for_adt(adt).fields.iter().map(|field| {
|
||||
field.ty(cx.tcx, substs)
|
||||
}).collect()
|
||||
}
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
|
||||
ctor: &Constructor,
|
||||
prefix: &[Pattern],
|
||||
@ -754,19 +788,18 @@ fn range_covered_by_constructor(tcx: TyCtxt, span: Span,
|
||||
Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
|
||||
}
|
||||
|
||||
fn patterns_for_variant<'a, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
subpatterns: &'a [FieldPattern<'tcx>],
|
||||
arity: usize)
|
||||
-> Vec<&'a Pattern<'tcx>>
|
||||
fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
|
||||
subpatterns: &'p [FieldPattern<'tcx>],
|
||||
wild_patterns: &[&'p Pattern<'tcx>])
|
||||
-> Vec<&'p Pattern<'tcx>>
|
||||
{
|
||||
let mut result = vec![cx.wild_pattern; arity];
|
||||
let mut result = wild_patterns.to_owned();
|
||||
|
||||
for subpat in subpatterns {
|
||||
result[subpat.field.index()] = &subpat.pattern;
|
||||
}
|
||||
|
||||
debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, arity, result);
|
||||
debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, wild_patterns, result);
|
||||
result
|
||||
}
|
||||
|
||||
@ -778,35 +811,41 @@ fn patterns_for_variant<'a, 'tcx>(
|
||||
/// different patterns.
|
||||
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
|
||||
/// fields filled with wild patterns.
|
||||
fn specialize<'a, 'tcx>(
|
||||
fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
||||
cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
r: &[&'a Pattern<'tcx>],
|
||||
constructor: &Constructor, col: usize, arity: usize)
|
||||
-> Option<Vec<&'a Pattern<'tcx>>>
|
||||
r: &[&'p Pattern<'tcx>],
|
||||
constructor: &Constructor,
|
||||
wild_patterns: &[&'p Pattern<'tcx>])
|
||||
-> Option<Vec<&'p Pattern<'tcx>>>
|
||||
{
|
||||
let pat = &r[col];
|
||||
let pat = &r[0];
|
||||
|
||||
let head: Option<Vec<&Pattern>> = match *pat.kind {
|
||||
PatternKind::Binding { .. } | PatternKind::Wild =>
|
||||
Some(vec![cx.wild_pattern; arity]),
|
||||
PatternKind::Binding { .. } | PatternKind::Wild => {
|
||||
Some(wild_patterns.to_owned())
|
||||
},
|
||||
|
||||
PatternKind::Variant { adt_def, variant_index, ref subpatterns } => {
|
||||
PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
|
||||
let ref variant = adt_def.variants[variant_index];
|
||||
if *constructor == Variant(variant.did) {
|
||||
Some(patterns_for_variant(cx, subpatterns, arity))
|
||||
Some(patterns_for_variant(subpatterns, wild_patterns))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
PatternKind::Leaf { ref subpatterns } => Some(patterns_for_variant(cx, subpatterns, arity)),
|
||||
PatternKind::Deref { ref subpattern } => Some(vec![subpattern]),
|
||||
PatternKind::Leaf { ref subpatterns } => {
|
||||
Some(patterns_for_variant(subpatterns, wild_patterns))
|
||||
}
|
||||
PatternKind::Deref { ref subpattern } => {
|
||||
Some(vec![subpattern])
|
||||
}
|
||||
|
||||
PatternKind::Constant { ref value } => {
|
||||
match *constructor {
|
||||
Slice(..) => match *value {
|
||||
ConstVal::ByteStr(ref data) => {
|
||||
if arity == data.len() {
|
||||
if wild_patterns.len() == data.len() {
|
||||
Some(cx.lower_byte_str_pattern(pat))
|
||||
} else {
|
||||
None
|
||||
@ -842,11 +881,14 @@ fn specialize<'a, 'tcx>(
|
||||
match *constructor {
|
||||
Slice(..) => {
|
||||
let pat_len = prefix.len() + suffix.len();
|
||||
if let Some(slice_count) = arity.checked_sub(pat_len) {
|
||||
if let Some(slice_count) = wild_patterns.len().checked_sub(pat_len) {
|
||||
if slice_count == 0 || slice.is_some() {
|
||||
Some(
|
||||
prefix.iter().chain(
|
||||
repeat(cx.wild_pattern).take(slice_count).chain(
|
||||
wild_patterns.iter().map(|p| *p)
|
||||
.skip(prefix.len())
|
||||
.take(slice_count)
|
||||
.chain(
|
||||
suffix.iter()
|
||||
)).collect())
|
||||
} else {
|
||||
@ -870,11 +912,10 @@ fn specialize<'a, 'tcx>(
|
||||
}
|
||||
}
|
||||
};
|
||||
debug!("specialize({:?}, {:?}) = {:?}", r[col], arity, head);
|
||||
debug!("specialize({:?}, {:?}) = {:?}", r[0], wild_patterns, head);
|
||||
|
||||
head.map(|mut head| {
|
||||
head.extend_from_slice(&r[..col]);
|
||||
head.extend_from_slice(&r[col + 1..]);
|
||||
head.extend_from_slice(&r[1 ..]);
|
||||
head
|
||||
})
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ use rustc::middle::expr_use_visitor as euv;
|
||||
use rustc::middle::mem_categorization::{cmt};
|
||||
use rustc::session::Session;
|
||||
use rustc::traits::Reveal;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::lint;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
|
||||
@ -36,7 +36,7 @@ use rustc_back::slice;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ptr::P;
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
struct OuterVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
|
||||
|
||||
@ -81,7 +81,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
|
||||
|
||||
match ex.node {
|
||||
hir::ExprMatch(ref scrut, ref arms, source) => {
|
||||
self.check_match(scrut, arms, source, ex.span);
|
||||
self.check_match(scrut, arms, source);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -132,8 +132,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||
&self,
|
||||
scrut: &hir::Expr,
|
||||
arms: &[hir::Arm],
|
||||
source: hir::MatchSource,
|
||||
span: Span)
|
||||
source: hir::MatchSource)
|
||||
{
|
||||
for arm in arms {
|
||||
// First, check legality of move bindings.
|
||||
@ -175,32 +174,14 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||
// Fourth, check for unreachable arms.
|
||||
check_arms(cx, &inlined_arms, source);
|
||||
|
||||
// Finally, check if the whole match expression is exhaustive.
|
||||
// Check for empty enum, because is_useful only works on inhabited types.
|
||||
let pat_ty = self.tcx.tables().node_id_to_type(scrut.id);
|
||||
if inlined_arms.is_empty() {
|
||||
if !pat_ty.is_uninhabited(Some(scrut.id), self.tcx) {
|
||||
// We know the type is inhabited, so this must be wrong
|
||||
let mut err = create_e0004(self.tcx.sess, span,
|
||||
format!("non-exhaustive patterns: type {} \
|
||||
is non-empty",
|
||||
pat_ty));
|
||||
span_help!(&mut err, span,
|
||||
"Please ensure that all possible cases are being handled; \
|
||||
possibly adding wildcards or more match arms.");
|
||||
err.emit();
|
||||
}
|
||||
// If the type *is* uninhabited, it's vacuously exhaustive
|
||||
return;
|
||||
}
|
||||
|
||||
let matrix: Matrix = inlined_arms
|
||||
.iter()
|
||||
.filter(|&&(_, guard)| guard.is_none())
|
||||
.flat_map(|arm| &arm.0)
|
||||
.map(|pat| vec![pat.0])
|
||||
.collect();
|
||||
check_exhaustive(cx, scrut.span, &matrix, source);
|
||||
let scrut_ty = cx.tcx.tables().node_id_to_type(scrut.id);
|
||||
check_exhaustive(cx, scrut_ty, scrut.span, &matrix, source);
|
||||
})
|
||||
}
|
||||
|
||||
@ -213,11 +194,18 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||
|
||||
MatchCheckCtxt::create_and_enter(self.tcx, pat.id, |ref mut cx| {
|
||||
let mut patcx = PatternContext::new(self.tcx);
|
||||
let pattern = patcx.lower_pattern(pat);
|
||||
let pattern_ty = pattern.ty;
|
||||
let pats : Matrix = vec![vec![
|
||||
expand_pattern(cx, patcx.lower_pattern(pat))
|
||||
expand_pattern(cx, pattern)
|
||||
]].into_iter().collect();
|
||||
|
||||
let witness = match is_useful(cx, &pats, &[cx.wild_pattern], ConstructWitness) {
|
||||
let wild_pattern = Pattern {
|
||||
ty: pattern_ty,
|
||||
span: DUMMY_SP,
|
||||
kind: box PatternKind::Wild,
|
||||
};
|
||||
let witness = match is_useful(cx, &pats, &[&wild_pattern], ConstructWitness) {
|
||||
UsefulWithWitness(witness) => witness,
|
||||
NotUseful => return,
|
||||
Useful => bug!()
|
||||
@ -359,10 +347,16 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
scrut_ty: Ty<'tcx>,
|
||||
sp: Span,
|
||||
matrix: &Matrix<'a, 'tcx>,
|
||||
source: hir::MatchSource) {
|
||||
match is_useful(cx, matrix, &[cx.wild_pattern], ConstructWitness) {
|
||||
let wild_pattern = Pattern {
|
||||
ty: scrut_ty,
|
||||
span: DUMMY_SP,
|
||||
kind: box PatternKind::Wild,
|
||||
};
|
||||
match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness) {
|
||||
UsefulWithWitness(pats) => {
|
||||
let witnesses = if pats.is_empty() {
|
||||
vec![cx.wild_pattern]
|
||||
|
@ -13,7 +13,8 @@ use eval;
|
||||
use rustc::lint;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::mir::{Field, BorrowKind, Mutability};
|
||||
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
|
||||
use rustc::ty::{self, TyCtxt, AdtDef, Ty, TypeVariants, Region};
|
||||
use rustc::ty::subst::{Substs, Kind};
|
||||
use rustc::hir::{self, PatKind};
|
||||
use rustc::hir::def::{Def, CtorKind};
|
||||
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
|
||||
@ -67,6 +68,7 @@ pub enum PatternKind<'tcx> {
|
||||
/// Foo(...) or Foo{...} or Foo, where `Foo` is a variant name from an adt with >1 variants
|
||||
Variant {
|
||||
adt_def: &'tcx AdtDef,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
variant_index: usize,
|
||||
subpatterns: Vec<FieldPattern<'tcx>>,
|
||||
},
|
||||
@ -534,11 +536,15 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
|
||||
{
|
||||
match def {
|
||||
Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
|
||||
let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
|
||||
let adt_def = self.tcx.lookup_adt_def(enum_id);
|
||||
let ty = self.tcx.tables().node_id_to_type(pat.id);
|
||||
let (adt_def, substs) = match ty.sty {
|
||||
TypeVariants::TyAdt(adt_def, substs) => (adt_def, substs),
|
||||
_ => span_bug!(pat.span, "inappropriate type for def"),
|
||||
};
|
||||
if adt_def.variants.len() > 1 {
|
||||
PatternKind::Variant {
|
||||
adt_def: adt_def,
|
||||
substs: substs,
|
||||
variant_index: adt_def.variant_index_with_id(variant_id),
|
||||
subpatterns: subpatterns,
|
||||
}
|
||||
@ -776,8 +782,9 @@ macro_rules! CloneImpls {
|
||||
}
|
||||
|
||||
CloneImpls!{ <'tcx>
|
||||
Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal,
|
||||
Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef
|
||||
Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal, Region,
|
||||
Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
|
||||
&'tcx Substs<'tcx>, &'tcx Kind<'tcx>
|
||||
}
|
||||
|
||||
impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
|
||||
@ -828,10 +835,12 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
|
||||
},
|
||||
PatternKind::Variant {
|
||||
adt_def,
|
||||
substs,
|
||||
variant_index,
|
||||
ref subpatterns,
|
||||
} => PatternKind::Variant {
|
||||
adt_def: adt_def.fold_with(folder),
|
||||
substs: substs.fold_with(folder),
|
||||
variant_index: variant_index.fold_with(folder),
|
||||
subpatterns: subpatterns.fold_with(folder)
|
||||
},
|
||||
|
@ -26,6 +26,7 @@ use build::{BlockAnd, BlockAndExtension, Builder};
|
||||
use build::matches::{Binding, MatchPair, Candidate};
|
||||
use hair::*;
|
||||
use rustc::mir::*;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
use std::mem;
|
||||
|
||||
@ -93,11 +94,28 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
PatternKind::Range { .. } |
|
||||
PatternKind::Variant { .. } |
|
||||
PatternKind::Slice { .. } => {
|
||||
Err(match_pair)
|
||||
}
|
||||
|
||||
PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
|
||||
let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| {
|
||||
let mut visited = FxHashSet::default();
|
||||
i == variant_index || v.is_uninhabited_recurse(&mut visited,
|
||||
None,
|
||||
self.hir.tcx(),
|
||||
substs,
|
||||
adt_def.adt_kind())
|
||||
});
|
||||
if irrefutable {
|
||||
let lvalue = match_pair.lvalue.downcast(adt_def, variant_index);
|
||||
candidate.match_pairs.extend(self.field_match_pairs(lvalue, subpatterns));
|
||||
Ok(())
|
||||
} else {
|
||||
Err(match_pair)
|
||||
}
|
||||
},
|
||||
|
||||
PatternKind::Array { ref prefix, ref slice, ref suffix } => {
|
||||
self.prefix_slice_suffix(&mut candidate.match_pairs,
|
||||
&match_pair.lvalue,
|
||||
|
@ -32,7 +32,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
/// It is a bug to call this with a simplifyable pattern.
|
||||
pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
|
||||
match *match_pair.pattern.kind {
|
||||
PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => {
|
||||
PatternKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => {
|
||||
Test {
|
||||
span: match_pair.pattern.span,
|
||||
kind: TestKind::Switch {
|
||||
@ -451,7 +451,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
// If we are performing a variant switch, then this
|
||||
// informs variant patterns, but nothing else.
|
||||
(&TestKind::Switch { adt_def: tested_adt_def, .. },
|
||||
&PatternKind::Variant { adt_def, variant_index, ref subpatterns }) => {
|
||||
&PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. }) => {
|
||||
assert_eq!(adt_def, tested_adt_def);
|
||||
let new_candidate =
|
||||
self.candidate_after_variant_switch(match_pair_index,
|
||||
|
60
src/test/run-pass/empty-types-in-patterns.rs
Normal file
60
src/test/run-pass/empty-types-in-patterns.rs
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
#![feature(never_type)]
|
||||
#![feature(slice_patterns)]
|
||||
#![allow(unreachable_patterns)]
|
||||
#![allow(unreachable_code)]
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn foo(z: !) {
|
||||
let x: Result<!, !> = Ok(z);
|
||||
|
||||
let Ok(_y) = x;
|
||||
let Err(_y) = x;
|
||||
|
||||
let x = [z; 1];
|
||||
|
||||
match x {};
|
||||
match x {
|
||||
[q] => q,
|
||||
};
|
||||
}
|
||||
|
||||
fn bar(nevers: &[!]) {
|
||||
match nevers {
|
||||
&[] => (),
|
||||
};
|
||||
|
||||
match nevers {
|
||||
&[] => (),
|
||||
&[_] => (),
|
||||
&[_, _, _, ..] => (),
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x: Result<u32, !> = Ok(123);
|
||||
let Ok(y) = x;
|
||||
|
||||
assert_eq!(123, y);
|
||||
|
||||
match x {
|
||||
Ok(y) => y,
|
||||
};
|
||||
|
||||
match x {
|
||||
Ok(y) => y,
|
||||
Err(e) => match e {},
|
||||
};
|
||||
|
||||
bar(&[]);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user