diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 3cd358047329..f244306a0cf4 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -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)) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3e33d246b6d1..ba389b98b8c4 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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, 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, 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) } } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index b517a77255e2..1577e87049cc 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -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>, 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 { + 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> + where I: Iterator> { // 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 /// /// 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> +{ + 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>> + r: &[&'p Pattern<'tcx>], + constructor: &Constructor, + wild_patterns: &[&'p Pattern<'tcx>]) + -> Option>> { - let pat = &r[col]; + let pat = &r[0]; let head: Option> = 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 }) } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index d6187f40b7f3..c3a033f4aa79 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -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] diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index b122d97a702f..ce2cd47572f5 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -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>, }, @@ -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) }, diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 71282dcf0ba0..c3414c591abb 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -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, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index cb449037aeba..8b4a013bad0a 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -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, diff --git a/src/test/run-pass/empty-types-in-patterns.rs b/src/test/run-pass/empty-types-in-patterns.rs new file mode 100644 index 000000000000..23705d36e3de --- /dev/null +++ b/src/test/run-pass/empty-types-in-patterns.rs @@ -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 or the MIT license +// , 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 = 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(&[]); +} +