diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 907c84b6f8cf..322ab115cda4 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -155,7 +155,6 @@ /// + If some constructors are missing from the matrix, it turns out we don't need to do /// anything special (because we know none of the integers are actually wildcards: i.e., we /// can't span wildcards using ranges). - use self::Constructor::*; use self::Usefulness::*; use self::WitnessPreference::*; @@ -163,31 +162,31 @@ use self::WitnessPreference::*; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::Idx; +use super::{compare_const_vals, PatternFoldable, PatternFolder}; use super::{FieldPat, Pat, PatKind, PatRange}; -use super::{PatternFoldable, PatternFolder, compare_const_vals}; use rustc::hir::def_id::DefId; -use rustc::hir::{RangeEnd, HirId}; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const}; -use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size}; +use rustc::hir::{HirId, RangeEnd}; +use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx}; +use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable}; -use rustc::mir::Field; -use rustc::mir::interpret::{ConstValue, Scalar, truncate, AllocId, Pointer}; -use rustc::util::common::ErrorReported; use rustc::lint; +use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar}; +use rustc::mir::Field; +use rustc::util::common::ErrorReported; use syntax::attr::{SignedInt, UnsignedInt}; use syntax_pos::{Span, DUMMY_SP}; use arena::TypedArena; -use smallvec::{SmallVec, smallvec}; -use std::cmp::{self, Ordering, min, max}; +use smallvec::{smallvec, SmallVec}; +use std::cmp::{self, max, min, Ordering}; +use std::convert::TryInto; use std::fmt; use std::iter::{FromIterator, IntoIterator}; use std::ops::RangeInclusive; use std::u128; -use std::convert::TryInto; pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> { LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat) @@ -216,11 +215,8 @@ impl LiteralExpander<'tcx> { // the easy case, deref a reference (ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => { let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id); - ConstValue::ByRef { - alloc, - offset: p.offset, - } - }, + ConstValue::ByRef { alloc, offset: p.offset } + } // unsize array to slice if pattern is array but match value or other patterns are slice (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => { assert_eq!(t, u); @@ -229,12 +225,11 @@ impl LiteralExpander<'tcx> { start: p.offset.bytes().try_into().unwrap(), end: n.eval_usize(self.tcx, ty::ParamEnv::empty()).try_into().unwrap(), } - }, + } // fat pointers stay the same - | (ConstValue::Slice { .. }, _, _) + (ConstValue::Slice { .. }, _, _) | (_, ty::Slice(_), ty::Slice(_)) - | (_, ty::Str, ty::Str) - => val, + | (_, ty::Str, ty::Str) => val, // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty), } @@ -247,30 +242,27 @@ impl PatternFolder<'tcx> for LiteralExpander<'tcx> { match (&pat.ty.kind, &*pat.kind) { ( &ty::Ref(_, rty, _), - &PatKind::Constant { value: Const { - val, - ty: ty::TyS { kind: ty::Ref(_, crty, _), .. }, - } }, - ) => { - Pat { - ty: pat.ty, - span: pat.span, - kind: box PatKind::Deref { - subpattern: Pat { - ty: rty, - span: pat.span, - kind: box PatKind::Constant { value: self.tcx.mk_const(Const { + &PatKind::Constant { + value: Const { val, ty: ty::TyS { kind: ty::Ref(_, crty, _), .. } }, + }, + ) => Pat { + ty: pat.ty, + span: pat.span, + kind: box PatKind::Deref { + subpattern: Pat { + ty: rty, + span: pat.span, + kind: box PatKind::Constant { + value: self.tcx.mk_const(Const { val: self.fold_const_value_deref(*val, rty, crty), ty: rty, - }) }, - } - } - } - } - (_, &PatKind::Binding { subpattern: Some(ref s), .. }) => { - s.fold_with(self) - } - _ => pat.super_fold_with(self) + }), + }, + }, + }, + }, + (_, &PatKind::Binding { subpattern: Some(ref s), .. }) => s.fold_with(self), + _ => pat.super_fold_with(self), } } } @@ -278,9 +270,8 @@ impl PatternFolder<'tcx> for LiteralExpander<'tcx> { impl<'tcx> Pat<'tcx> { fn is_wildcard(&self) -> bool { match *self.kind { - PatKind::Binding { subpattern: None, .. } | PatKind::Wild => - true, - _ => false + PatKind::Binding { subpattern: None, .. } | PatKind::Wild => true, + _ => false, } } } @@ -316,15 +307,14 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { write!(f, "\n")?; let &Matrix(ref m) = self; - let pretty_printed_matrix: Vec> = m.iter().map(|row| { - row.iter().map(|pat| format!("{:?}", pat)).collect() - }).collect(); + let pretty_printed_matrix: Vec> = + m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect(); let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0); assert!(m.iter().all(|row| row.len() == column_count)); - let column_widths: Vec = (0..column_count).map(|col| { - pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0) - }).collect(); + let column_widths: Vec = (0..column_count) + .map(|col| pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0)) + .collect(); let total_width = column_widths.iter().cloned().sum::() + column_count * 3 + 1; let br = "+".repeat(total_width); @@ -345,7 +335,8 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { impl<'p, 'tcx> FromIterator; 2]>> for Matrix<'p, 'tcx> { fn from_iter(iter: T) -> Self - where T: IntoIterator; 2]>> + where + T: IntoIterator; 2]>>, { Matrix(iter.into_iter().collect()) } @@ -461,7 +452,7 @@ impl<'tcx> Constructor<'tcx> { VariantIdx::new(0) } ConstantValue(c, _) => crate::const_eval::const_variant_index(cx.tcx, cx.param_env, c), - _ => bug!("bad constructor {:?} for adt {:?}", self, adt) + _ => bug!("bad constructor {:?} for adt {:?}", self, adt), } } @@ -488,14 +479,14 @@ impl<'tcx> Constructor<'tcx> { pub enum Usefulness<'tcx> { Useful, UsefulWithWitness(Vec>), - NotUseful + NotUseful, } impl<'tcx> Usefulness<'tcx> { fn is_useful(&self) -> bool { match *self { NotUseful => false, - _ => true + _ => true, } } } @@ -503,7 +494,7 @@ impl<'tcx> Usefulness<'tcx> { #[derive(Copy, Clone, Debug)] pub enum WitnessPreference { ConstructWitness, - LeaveOutWitness + LeaveOutWitness, } #[derive(Copy, Clone, Debug)] @@ -558,16 +549,13 @@ impl<'tcx> Witness<'tcx> { mut self, cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor<'tcx>, - ty: Ty<'tcx>) - -> Self - { + ty: Ty<'tcx>, + ) -> Self { let sub_pattern_tys = constructor_sub_pattern_tys(cx, ctor, ty); - self.0.extend(sub_pattern_tys.into_iter().map(|ty| { - Pat { - ty, - span: DUMMY_SP, - kind: box PatKind::Wild, - } + self.0.extend(sub_pattern_tys.into_iter().map(|ty| Pat { + ty, + span: DUMMY_SP, + kind: box PatKind::Wild, })); self.apply_constructor(cx, ctor, ty) } @@ -587,25 +575,21 @@ impl<'tcx> Witness<'tcx> { /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } fn apply_constructor<'a>( mut self, - cx: &MatchCheckCtxt<'a,'tcx>, + cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor<'tcx>, - ty: Ty<'tcx>) - -> Self - { + ty: Ty<'tcx>, + ) -> Self { let arity = constructor_arity(cx, ctor, ty); let pat = { let len = self.0.len() as u64; let mut pats = self.0.drain((len - arity) as usize..).rev(); match ty.kind { - ty::Adt(..) | - ty::Tuple(..) => { - let pats = pats.enumerate().map(|(i, p)| { - FieldPat { - field: Field::new(i), - pattern: p - } - }).collect(); + ty::Adt(..) | ty::Tuple(..) => { + let pats = pats + .enumerate() + .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) + .collect(); if let ty::Adt(adt, substs) = ty.kind { if adt.is_enum() { @@ -613,7 +597,7 @@ impl<'tcx> Witness<'tcx> { adt_def: adt, substs, variant_index: ctor.variant_index_for_adt(cx, adt), - subpatterns: pats + subpatterns: pats, } } else { PatKind::Leaf { subpatterns: pats } @@ -623,37 +607,25 @@ impl<'tcx> Witness<'tcx> { } } - ty::Ref(..) => { - PatKind::Deref { subpattern: pats.nth(0).unwrap() } - } + ty::Ref(..) => PatKind::Deref { subpattern: pats.nth(0).unwrap() }, ty::Slice(_) | ty::Array(..) => { - PatKind::Slice { - prefix: pats.collect(), - slice: None, - suffix: vec![] - } + PatKind::Slice { prefix: pats.collect(), slice: None, suffix: vec![] } } - _ => { - match *ctor { - ConstantValue(value, _) => PatKind::Constant { value }, - ConstantRange(lo, hi, ty, end, _) => PatKind::Range(PatRange { - lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)), - hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)), - end, - }), - _ => PatKind::Wild, - } - } + _ => match *ctor { + ConstantValue(value, _) => PatKind::Constant { value }, + ConstantRange(lo, hi, ty, end, _) => PatKind::Range(PatRange { + lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)), + hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)), + end, + }), + _ => PatKind::Wild, + }, } }; - self.0.push(Pat { - ty, - span: DUMMY_SP, - kind: Box::new(pat), - }); + self.0.push(Pat { ty, span: DUMMY_SP, kind: Box::new(pat) }); self } @@ -672,37 +644,33 @@ fn all_constructors<'a, 'tcx>( ) -> Vec> { debug!("all_constructors({:?})", pcx.ty); let ctors = match pcx.ty.kind { - ty::Bool => { - [true, false].iter().map(|&b| { - ConstantValue(ty::Const::from_bool(cx.tcx, b), pcx.span) - }).collect() - } + ty::Bool => [true, false] + .iter() + .map(|&b| ConstantValue(ty::Const::from_bool(cx.tcx, b), pcx.span)) + .collect(), ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { let len = len.eval_usize(cx.tcx, cx.param_env); - if len != 0 && cx.is_uninhabited(sub_ty) { - vec![] - } else { - vec![Slice(len)] - } + if len != 0 && cx.is_uninhabited(sub_ty) { vec![] } else { vec![Slice(len)] } } // Treat arrays of a constant but unknown length like slices. - ty::Array(ref sub_ty, _) | - ty::Slice(ref sub_ty) => { + ty::Array(ref sub_ty, _) | ty::Slice(ref sub_ty) => { if cx.is_uninhabited(sub_ty) { vec![Slice(0)] } else { - (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect() + (0..pcx.max_slice_length + 1).map(|length| Slice(length)).collect() } } - ty::Adt(def, substs) if def.is_enum() => { - def.variants.iter() - .filter(|v| { - !cx.tcx.features().exhaustive_patterns || - !v.uninhabited_from(cx.tcx, substs, def.adt_kind()).contains(cx.tcx, cx.module) - }) - .map(|v| Variant(v.def_id)) - .collect() - } + ty::Adt(def, substs) if def.is_enum() => def + .variants + .iter() + .filter(|v| { + !cx.tcx.features().exhaustive_patterns + || !v + .uninhabited_from(cx.tcx, substs, def.adt_kind()) + .contains(cx.tcx, cx.module) + }) + .map(|v| Variant(v.def_id)) + .collect(), ty::Char => { vec![ // The valid Unicode Scalar Value ranges. @@ -822,15 +790,13 @@ where PatKind::Constant { value } => { // extract the length of an array/slice from a constant match (value.val, &value.ty.kind) { - (_, ty::Array(_, n)) => max_fixed_len = cmp::max( - max_fixed_len, - n.eval_usize(cx.tcx, cx.param_env), - ), - (ConstValue::Slice{ start, end, .. }, ty::Slice(_)) => max_fixed_len = cmp::max( - max_fixed_len, - (end - start) as u64, - ), - _ => {}, + (_, ty::Array(_, n)) => { + max_fixed_len = cmp::max(max_fixed_len, n.eval_usize(cx.tcx, cx.param_env)) + } + (ConstValue::Slice { start, end, .. }, ty::Slice(_)) => { + max_fixed_len = cmp::max(max_fixed_len, (end - start) as u64) + } + _ => {} } } PatKind::Slice { ref prefix, slice: None, ref suffix } => { @@ -907,7 +873,7 @@ impl<'tcx> IntRange<'tcx> { // This is a more general form of the previous branch. val } else { - return None + return None; }; let val = val ^ bias; Some(IntRange { range: val..=val, ty, span }) @@ -978,7 +944,7 @@ impl<'tcx> IntRange<'tcx> { } box PatKind::AscribeUserType { ref subpattern, .. } => { pat = subpattern; - }, + } _ => return None, } } @@ -991,7 +957,7 @@ impl<'tcx> IntRange<'tcx> { let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128; 1u128 << (bits - 1) } - _ => 0 + _ => 0, } } @@ -1020,34 +986,43 @@ impl<'tcx> IntRange<'tcx> { param_env: ty::ParamEnv<'tcx>, ranges: Vec>, ) -> Vec> { - let ranges = ranges.into_iter().filter_map(|r| { - IntRange::from_ctor(tcx, param_env, &r).map(|i| i.range) - }); + let ranges = ranges + .into_iter() + .filter_map(|r| IntRange::from_ctor(tcx, param_env, &r).map(|i| i.range)); let mut remaining_ranges = vec![]; let ty = self.ty; let (lo, hi) = self.range.into_inner(); for subrange in ranges { let (subrange_lo, subrange_hi) = subrange.into_inner(); - if lo > subrange_hi || subrange_lo > hi { + if lo > subrange_hi || subrange_lo > hi { // The pattern doesn't intersect with the subrange at all, // so the subrange remains untouched. - remaining_ranges.push( - Self::range_to_ctor(tcx, ty, subrange_lo..=subrange_hi, self.span), - ); + remaining_ranges.push(Self::range_to_ctor( + tcx, + ty, + subrange_lo..=subrange_hi, + self.span, + )); } else { if lo > subrange_lo { // The pattern intersects an upper section of the // subrange, so a lower section will remain. - remaining_ranges.push( - Self::range_to_ctor(tcx, ty, subrange_lo..=(lo - 1), self.span), - ); + remaining_ranges.push(Self::range_to_ctor( + tcx, + ty, + subrange_lo..=(lo - 1), + self.span, + )); } if hi < subrange_hi { // The pattern intersects a lower section of the // subrange, so an upper section will remain. - remaining_ranges.push( - Self::range_to_ctor(tcx, ty, (hi + 1)..=subrange_hi, self.span), - ); + remaining_ranges.push(Self::range_to_ctor( + tcx, + ty, + (hi + 1)..=subrange_hi, + self.span, + )); } } } @@ -1205,12 +1180,13 @@ pub fn is_useful<'p, 'a, 'tcx>( } } else { NotUseful - } + }; }; assert!(rows.iter().all(|r| r.len() == v.len())); - let (ty, span) = rows.iter() + let (ty, span) = rows + .iter() .map(|r| (r[0].ty, r[0].span)) .find(|(ty, _)| !ty.references_error()) .unwrap_or((v[0].ty, v[0].span)); @@ -1244,16 +1220,25 @@ pub fn is_useful<'p, 'a, 'tcx>( if let Some(constructors) = pat_constructors(cx, v[0], pcx) { debug!("is_useful - expanding constructors: {:#?}", constructors); split_grouped_constructors( - cx.tcx, cx.param_env, constructors, matrix, pcx.ty, pcx.span, Some(hir_id), - ).into_iter().map(|c| - is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id) - ).find(|result| result.is_useful()).unwrap_or(NotUseful) + cx.tcx, + cx.param_env, + constructors, + matrix, + pcx.ty, + pcx.span, + Some(hir_id), + ) + .into_iter() + .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id)) + .find(|result| result.is_useful()) + .unwrap_or(NotUseful) } else { debug!("is_useful - expanding wildcard"); - let used_ctors: Vec> = rows.iter().flat_map(|row| { - pat_constructors(cx, row[0], pcx).unwrap_or(vec![]) - }).collect(); + let used_ctors: Vec> = rows + .iter() + .flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![])) + .collect(); debug!("used_ctors = {:#?}", used_ctors); // `all_ctors` are all the constructors for the given type, which // should all be represented (or caught with the wild pattern `_`). @@ -1284,35 +1269,47 @@ pub fn is_useful<'p, 'a, 'tcx>( // the set is empty, but we only fully construct them on-demand, // because they're rarely used and can be big. let cheap_missing_ctors = compute_missing_ctors( - MissingCtorsInfo::Emptiness, cx.tcx, cx.param_env, &all_ctors, &used_ctors, + MissingCtorsInfo::Emptiness, + cx.tcx, + cx.param_env, + &all_ctors, + &used_ctors, ); let is_privately_empty = all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty); let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty); - debug!("cheap_missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}", - cheap_missing_ctors, is_privately_empty, is_declared_nonexhaustive); + debug!( + "cheap_missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}", + cheap_missing_ctors, is_privately_empty, is_declared_nonexhaustive + ); // For privately empty and non-exhaustive enums, we work as if there were an "extra" // `_` constructor for the type, so we can never match over all constructors. - let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive || - (pcx.ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching); + let is_non_exhaustive = is_privately_empty + || is_declared_nonexhaustive + || (pcx.ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching); if cheap_missing_ctors == MissingCtors::Empty && !is_non_exhaustive { split_grouped_constructors( - cx.tcx, cx.param_env, all_ctors, matrix, pcx.ty, DUMMY_SP, None, + cx.tcx, + cx.param_env, + all_ctors, + matrix, + pcx.ty, + DUMMY_SP, + None, ) - .into_iter() - .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id)) - .find(|result| result.is_useful()) - .unwrap_or(NotUseful) + .into_iter() + .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id)) + .find(|result| result.is_useful()) + .unwrap_or(NotUseful) } else { - let matrix = rows.iter().filter_map(|r| { - if r[0].is_wildcard() { - Some(SmallVec::from_slice(&r[1..])) - } else { - None - } - }).collect(); + let matrix = rows + .iter() + .filter_map(|r| { + if r[0].is_wildcard() { Some(SmallVec::from_slice(&r[1..])) } else { None } + }) + .collect(); match is_useful(cx, &matrix, &v[1..], witness, hir_id) { UsefulWithWitness(pats) => { let cx = &*cx; @@ -1363,35 +1360,43 @@ pub fn is_useful<'p, 'a, 'tcx>( let new_witnesses = if is_non_exhaustive || used_ctors.is_empty() { // All constructors are unused. Add wild patterns // rather than each individual constructor. - pats.into_iter().map(|mut witness| { - witness.0.push(Pat { - ty: pcx.ty, - span: DUMMY_SP, - kind: box PatKind::Wild, - }); - witness - }).collect() + pats.into_iter() + .map(|mut witness| { + witness.0.push(Pat { + ty: pcx.ty, + span: DUMMY_SP, + kind: box PatKind::Wild, + }); + witness + }) + .collect() } else { let expensive_missing_ctors = compute_missing_ctors( - MissingCtorsInfo::Ctors, cx.tcx, cx.param_env, &all_ctors, &used_ctors, + MissingCtorsInfo::Ctors, + cx.tcx, + cx.param_env, + &all_ctors, + &used_ctors, ); if let MissingCtors::Ctors(missing_ctors) = expensive_missing_ctors { - pats.into_iter().flat_map(|witness| { - missing_ctors.iter().map(move |ctor| { - // Extends the witness with a "wild" version of this - // constructor, that matches everything that can be built with - // it. For example, if `ctor` is a `Constructor::Variant` for - // `Option::Some`, this pushes the witness for `Some(_)`. - witness.clone().push_wild_constructor(cx, ctor, pcx.ty) + pats.into_iter() + .flat_map(|witness| { + missing_ctors.iter().map(move |ctor| { + // Extends the witness with a "wild" version of this + // constructor, that matches everything that can be built with + // it. For example, if `ctor` is a `Constructor::Variant` for + // `Option::Some`, this pushes the witness for `Some(_)`. + witness.clone().push_wild_constructor(cx, ctor, pcx.ty) + }) }) - }).collect() + .collect() } else { bug!("cheap missing ctors") } }; UsefulWithWitness(new_witnesses) } - result => result + result => result, } } } @@ -1410,29 +1415,22 @@ fn is_useful_specialized<'p, 'a, 'tcx>( ) -> Usefulness<'tcx> { debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty); let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty); - let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| { - Pat { - ty, - span: DUMMY_SP, - kind: box PatKind::Wild, - } - }).collect(); + let wild_patterns_owned: Vec<_> = + sub_pat_tys.iter().map(|ty| Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild }).collect(); let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect(); - let matrix = Matrix( - m.iter() - .filter_map(|r| specialize(cx, &r, &ctor, &wild_patterns)) - .collect() - ); + let matrix = + Matrix(m.iter().filter_map(|r| specialize(cx, &r, &ctor, &wild_patterns)).collect()); match specialize(cx, v, &ctor, &wild_patterns) { Some(v) => match is_useful(cx, &matrix, &v, witness, hir_id) { UsefulWithWitness(witnesses) => UsefulWithWitness( - witnesses.into_iter() + witnesses + .into_iter() .map(|witness| witness.apply_constructor(cx, &ctor, lty)) - .collect() + .collect(), ), - result => result - } - None => NotUseful + result => result, + }, + None => NotUseful, } } @@ -1450,32 +1448,28 @@ fn pat_constructors<'tcx>( pcx: PatCtxt<'tcx>, ) -> Option>> { match *pat.kind { - PatKind::AscribeUserType { ref subpattern, .. } => - pat_constructors(cx, subpattern, pcx), + PatKind::AscribeUserType { ref subpattern, .. } => pat_constructors(cx, subpattern, pcx), PatKind::Binding { .. } | PatKind::Wild => None, PatKind::Leaf { .. } | PatKind::Deref { .. } => Some(vec![Single]), PatKind::Variant { adt_def, variant_index, .. } => { Some(vec![Variant(adt_def.variants[variant_index].def_id)]) } PatKind::Constant { value } => Some(vec![ConstantValue(value, pat.span)]), - PatKind::Range(PatRange { lo, hi, end }) => - Some(vec![ConstantRange( - lo.eval_bits(cx.tcx, cx.param_env, lo.ty), - hi.eval_bits(cx.tcx, cx.param_env, hi.ty), - lo.ty, - end, - pat.span, - )]), + PatKind::Range(PatRange { lo, hi, end }) => Some(vec![ConstantRange( + lo.eval_bits(cx.tcx, cx.param_env, lo.ty), + hi.eval_bits(cx.tcx, cx.param_env, hi.ty), + lo.ty, + end, + pat.span, + )]), PatKind::Array { .. } => match pcx.ty.kind { - ty::Array(_, length) => Some(vec![ - Slice(length.eval_usize(cx.tcx, cx.param_env)) - ]), - _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty) + ty::Array(_, length) => Some(vec![Slice(length.eval_usize(cx.tcx, cx.param_env))]), + _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty), }, PatKind::Slice { ref prefix, ref slice, ref suffix } => { let pat_len = prefix.len() as u64 + suffix.len() as u64; if slice.is_some() { - Some((pat_len..pcx.max_slice_length+1).map(Slice).collect()) + Some((pat_len..pcx.max_slice_length + 1).map(Slice).collect()) } else { Some(vec![Slice(pat_len)]) } @@ -1498,13 +1492,11 @@ fn constructor_arity(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor<'tcx>, ty ty::Slice(..) | ty::Array(..) => match *ctor { Slice(length) => length, ConstantValue(..) => 0, - _ => bug!("bad slice pattern {:?} {:?}", ctor, ty) - } + _ => bug!("bad slice pattern {:?} {:?}", ctor, ty), + }, ty::Ref(..) => 1, - ty::Adt(adt, _) => { - adt.variants[ctor.variant_index_for_adt(cx, adt)].fields.len() as u64 - } - _ => 0 + ty::Adt(adt, _) => adt.variants[ctor.variant_index_for_adt(cx, adt)].fields.len() as u64, + _ => 0, } } @@ -1523,8 +1515,8 @@ fn constructor_sub_pattern_tys<'a, 'tcx>( ty::Slice(ty) | ty::Array(ty, _) => match *ctor { Slice(length) => (0..length).map(|_| ty).collect(), ConstantValue(..) => vec![], - _ => bug!("bad slice pattern {:?} {:?}", ctor, ty) - } + _ => bug!("bad slice pattern {:?} {:?}", ctor, ty), + }, ty::Ref(_, rty, _) => vec![rty], ty::Adt(adt, substs) => { if adt.is_box() { @@ -1533,30 +1525,36 @@ fn constructor_sub_pattern_tys<'a, 'tcx>( } else { let variant = &adt.variants[ctor.variant_index_for_adt(cx, adt)]; let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(ty); - variant.fields.iter().map(|field| { - let is_visible = adt.is_enum() - || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs)); - match (is_visible, is_non_exhaustive, is_uninhabited) { - // Treat all uninhabited types in non-exhaustive variants as `TyErr`. - (_, true, true) => cx.tcx.types.err, - // 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. - (false, ..) => cx.tcx.types.err, - (true, ..) => { - let ty = field.ty(cx.tcx, substs); - match ty.kind { - // If the field type returned is an array of an unknown - // size return an TyErr. - ty::Array(_, len) - if len.try_eval_usize(cx.tcx, cx.param_env).is_none() => - cx.tcx.types.err, - _ => ty, + variant + .fields + .iter() + .map(|field| { + let is_visible = + adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); + let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs)); + match (is_visible, is_non_exhaustive, is_uninhabited) { + // Treat all uninhabited types in non-exhaustive variants as `TyErr`. + (_, true, true) => cx.tcx.types.err, + // 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. + (false, ..) => cx.tcx.types.err, + (true, ..) => { + let ty = field.ty(cx.tcx, substs); + match ty.kind { + // If the field type returned is an array of an unknown + // size return an TyErr. + ty::Array(_, len) + if len.try_eval_usize(cx.tcx, cx.param_env).is_none() => + { + cx.tcx.types.err + } + _ => ty, + } } - }, - } - }).collect() + } + }) + .collect() } } _ => vec![], @@ -1581,17 +1579,20 @@ fn slice_pat_covered_by_const<'tcx>( let n = n.eval_usize(tcx, param_env); let ptr = Pointer::new(AllocId(0), offset); alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap() - }, + } (ConstValue::Slice { data, start, end }, ty::Slice(t)) => { assert_eq!(*t, tcx.types.u8); let ptr = Pointer::new(AllocId(0), Size::from_bytes(start as u64)); data.get_bytes(&tcx, ptr, Size::from_bytes((end - start) as u64)).unwrap() - }, + } // FIXME(oli-obk): create a way to extract fat pointers from ByRef (_, ty::Slice(_)) => return Ok(false), _ => bug!( "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}", - const_val, prefix, slice, suffix, + const_val, + prefix, + slice, + suffix, ), }; @@ -1600,9 +1601,10 @@ fn slice_pat_covered_by_const<'tcx>( return Ok(false); } - for (ch, pat) in - data[..prefix.len()].iter().zip(prefix).chain( - data[data.len()-suffix.len()..].iter().zip(suffix)) + for (ch, pat) in data[..prefix.len()] + .iter() + .zip(prefix) + .chain(data[data.len() - suffix.len()..].iter().zip(suffix)) { match pat.kind { box PatKind::Constant { value } => { @@ -1715,7 +1717,8 @@ fn split_grouped_constructors<'p, 'tcx>( let mut overlaps = vec![]; // `borders` is the set of borders between equivalence classes: each equivalence // class lies between 2 borders. - let row_borders = m.iter() + let row_borders = m + .iter() .flat_map(|row| { IntRange::from_pat(tcx, param_env, row[0]).map(|r| (r, row.len())) }) @@ -1745,8 +1748,8 @@ fn split_grouped_constructors<'p, 'tcx>( // We're going to iterate through every pair of borders, making sure that each // represents an interval of nonnegative length, and convert each such interval // into a constructor. - for IntRange { range, .. } in borders.windows(2).filter_map(|window| { - match (window[0], window[1]) { + for IntRange { range, .. } in + borders.windows(2).filter_map(|window| match (window[0], window[1]) { (Border::JustBefore(n), Border::JustBefore(m)) => { if n < m { Some(IntRange { range: n..=(m - 1), ty, span }) @@ -1758,8 +1761,8 @@ fn split_grouped_constructors<'p, 'tcx>( Some(IntRange { range: n..=u128::MAX, ty, span }) } (Border::AfterMax, _) => None, - } - }) { + }) + { split_ctors.push(IntRange::range_to_ctor(tcx, ty, range, span)); } } @@ -1788,10 +1791,13 @@ fn lint_overlapping_patterns( err.span_label(ctor_range.span, "overlapping patterns"); for int_range in overlaps { // Use the real type for user display of the ranges: - err.span_label(int_range.span, &format!( - "this range overlaps on `{}`", - IntRange::range_to_ctor(tcx, ty, int_range.range, DUMMY_SP).display(tcx), - )); + err.span_label( + int_range.span, + &format!( + "this range overlaps on `{}`", + IntRange::range_to_ctor(tcx, ty, int_range.range, DUMMY_SP).display(tcx), + ), + ); } err.emit(); } @@ -1809,8 +1815,9 @@ fn constructor_covered_by_range<'tcx>( _ => bug!("`constructor_covered_by_range` called with {:?}", pat), }; trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty); - let cmp_from = |c_from| compare_const_vals(tcx, c_from, from, param_env, ty) - .map(|res| res != Ordering::Less); + let cmp_from = |c_from| { + compare_const_vals(tcx, c_from, from, param_env, ty).map(|res| res != Ordering::Less) + }; let cmp_to = |c_to| compare_const_vals(tcx, c_to, to, param_env, ty); macro_rules! some_or_ok { ($e:expr) => { @@ -1823,37 +1830,31 @@ fn constructor_covered_by_range<'tcx>( match *ctor { ConstantValue(value, _) => { let to = some_or_ok!(cmp_to(value)); - let end = (to == Ordering::Less) || - (end == RangeEnd::Included && to == Ordering::Equal); + let end = + (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); Ok(some_or_ok!(cmp_from(value)) && end) - }, + } ConstantRange(from, to, ty, RangeEnd::Included, _) => { - let to = some_or_ok!(cmp_to(ty::Const::from_bits( - tcx, - to, - ty::ParamEnv::empty().and(ty), - ))); - let end = (to == Ordering::Less) || - (end == RangeEnd::Included && to == Ordering::Equal); + let to = + some_or_ok!(cmp_to(ty::Const::from_bits(tcx, to, ty::ParamEnv::empty().and(ty),))); + let end = + (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); Ok(some_or_ok!(cmp_from(ty::Const::from_bits( tcx, from, ty::ParamEnv::empty().and(ty), ))) && end) - }, + } ConstantRange(from, to, ty, RangeEnd::Excluded, _) => { - let to = some_or_ok!(cmp_to(ty::Const::from_bits( - tcx, - to, - ty::ParamEnv::empty().and(ty) - ))); - let end = (to == Ordering::Less) || - (end == RangeEnd::Excluded && to == Ordering::Equal); + let to = + some_or_ok!(cmp_to(ty::Const::from_bits(tcx, to, ty::ParamEnv::empty().and(ty)))); + let end = + (to == Ordering::Less) || (end == RangeEnd::Excluded && to == Ordering::Equal); Ok(some_or_ok!(cmp_from(ty::Const::from_bits( tcx, from, - ty::ParamEnv::empty().and(ty))) - ) && end) + ty::ParamEnv::empty().and(ty) + ))) && end) } Single => Ok(true), _ => bug!(), @@ -1899,9 +1900,7 @@ fn specialize<'p, 'a: 'p, 'tcx>( specialize(cx, ::std::slice::from_ref(&subpattern), constructor, wild_patterns) } - PatKind::Binding { .. } | PatKind::Wild => { - Some(SmallVec::from_slice(wild_patterns)) - } + PatKind::Binding { .. } | PatKind::Wild => Some(SmallVec::from_slice(wild_patterns)), PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { let ref variant = adt_def.variants[variant_index]; @@ -1915,9 +1914,7 @@ fn specialize<'p, 'a: 'p, 'tcx>( Some(patterns_for_variant(cx, subpatterns, wild_patterns, false)) } - PatKind::Deref { ref subpattern } => { - Some(smallvec![subpattern]) - } + PatKind::Deref { ref subpattern } => Some(smallvec![subpattern]), PatKind::Constant { value } if constructor.is_slice() => { // We extract an `Option` for the pointer because slices of zero @@ -1925,39 +1922,28 @@ fn specialize<'p, 'a: 'p, 'tcx>( // just integers. The only time they should be pointing to memory // is when they are subslices of nonzero slices. let (alloc, offset, n, ty) = match value.ty.kind { - ty::Array(t, n) => { - match value.val { - ConstValue::ByRef { offset, alloc, .. } => ( - alloc, - offset, - n.eval_usize(cx.tcx, cx.param_env), - t, - ), - _ => span_bug!( - pat.span, - "array pattern is {:?}", value, - ), + ty::Array(t, n) => match value.val { + ConstValue::ByRef { offset, alloc, .. } => { + (alloc, offset, n.eval_usize(cx.tcx, cx.param_env), t) } + _ => span_bug!(pat.span, "array pattern is {:?}", value,), }, ty::Slice(t) => { match value.val { - ConstValue::Slice { data, start, end } => ( - data, - Size::from_bytes(start as u64), - (end - start) as u64, - t, - ), + ConstValue::Slice { data, start, end } => { + (data, Size::from_bytes(start as u64), (end - start) as u64, t) + } ConstValue::ByRef { .. } => { // FIXME(oli-obk): implement `deref` for `ConstValue` return None; - }, + } _ => span_bug!( pat.span, "slice pattern constant must be scalar pair but is {:?}", value, ), } - }, + } _ => span_bug!( pat.span, "unexpected const-val {:?} with ctor {:?}", @@ -1969,41 +1955,37 @@ fn specialize<'p, 'a: 'p, 'tcx>( // convert a constant slice/array pattern to a list of patterns. let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?; let ptr = Pointer::new(AllocId(0), offset); - (0..n).map(|i| { - let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?; - let scalar = alloc.read_scalar( - &cx.tcx, ptr, layout.size, - ).ok()?; - let scalar = scalar.not_undef().ok()?; - let value = ty::Const::from_scalar(cx.tcx, scalar, ty); - let pattern = Pat { - ty, - span: pat.span, - kind: box PatKind::Constant { value }, - }; - Some(&*cx.pattern_arena.alloc(pattern)) - }).collect() + (0..n) + .map(|i| { + let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?; + let scalar = alloc.read_scalar(&cx.tcx, ptr, layout.size).ok()?; + let scalar = scalar.not_undef().ok()?; + let value = ty::Const::from_scalar(cx.tcx, scalar, ty); + let pattern = + Pat { ty, span: pat.span, kind: box PatKind::Constant { value } }; + Some(&*cx.pattern_arena.alloc(pattern)) + }) + .collect() } else { None } } - PatKind::Constant { .. } | - PatKind::Range { .. } => { + PatKind::Constant { .. } | PatKind::Range { .. } => { // If the constructor is a: // - Single value: add a row if the pattern contains the constructor. // - Range: add a row if the constructor intersects the pattern. if should_treat_range_exhaustively(cx.tcx, constructor) { - match (IntRange::from_ctor(cx.tcx, cx.param_env, constructor), - IntRange::from_pat(cx.tcx, cx.param_env, pat)) { - (Some(ctor), Some(pat)) => { - ctor.intersection(&pat).map(|_| { - let (pat_lo, pat_hi) = pat.range.into_inner(); - let (ctor_lo, ctor_hi) = ctor.range.into_inner(); - assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi); - smallvec![] - }) - } + match ( + IntRange::from_ctor(cx.tcx, cx.param_env, constructor), + IntRange::from_pat(cx.tcx, cx.param_env, pat), + ) { + (Some(ctor), Some(pat)) => ctor.intersection(&pat).map(|_| { + let (pat_lo, pat_hi) = pat.range.into_inner(); + let (ctor_lo, ctor_hi) = ctor.range.into_inner(); + assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi); + smallvec![] + }), _ => None, } } else { @@ -2019,39 +2001,49 @@ fn specialize<'p, 'a: 'p, 'tcx>( } } - PatKind::Array { ref prefix, ref slice, ref suffix } | - PatKind::Slice { ref prefix, ref slice, ref suffix } => { - match *constructor { - Slice(..) => { - let pat_len = prefix.len() + suffix.len(); - if let Some(slice_count) = wild_patterns.len().checked_sub(pat_len) { - if slice_count == 0 || slice.is_some() { - Some(prefix.iter().chain( - wild_patterns.iter().map(|p| *p) - .skip(prefix.len()) - .take(slice_count) - .chain(suffix.iter()) - ).collect()) - } else { - None - } + PatKind::Array { ref prefix, ref slice, ref suffix } + | PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor { + Slice(..) => { + let pat_len = prefix.len() + suffix.len(); + if let Some(slice_count) = wild_patterns.len().checked_sub(pat_len) { + if slice_count == 0 || slice.is_some() { + Some( + prefix + .iter() + .chain( + wild_patterns + .iter() + .map(|p| *p) + .skip(prefix.len()) + .take(slice_count) + .chain(suffix.iter()), + ) + .collect(), + ) } else { None } + } else { + None } - ConstantValue(cv, _) => { - match slice_pat_covered_by_const( - cx.tcx, pat.span, cv, prefix, slice, suffix, cx.param_env, - ) { - Ok(true) => Some(smallvec![]), - Ok(false) => None, - Err(ErrorReported) => None - } - } - _ => span_bug!(pat.span, - "unexpected ctor {:?} for slice pat", constructor) } - } + ConstantValue(cv, _) => { + match slice_pat_covered_by_const( + cx.tcx, + pat.span, + cv, + prefix, + slice, + suffix, + cx.param_env, + ) { + Ok(true) => Some(smallvec![]), + Ok(false) => None, + Err(ErrorReported) => None, + } + } + _ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor), + }, PatKind::Or { .. } => { bug!("support for or-patterns has not been fully implemented yet."); @@ -2060,7 +2052,7 @@ fn specialize<'p, 'a: 'p, 'tcx>( debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head); head.map(|mut head| { - head.extend_from_slice(&r[1 ..]); + head.extend_from_slice(&r[1..]); head }) } diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 77f3768172fb..ecfe43c65747 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -1,25 +1,25 @@ -use super::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful}; use super::_match::Usefulness::*; use super::_match::WitnessPreference::*; +use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix}; -use super::{PatCtxt, PatternError, PatKind}; +use super::{PatCtxt, PatKind, PatternError}; -use rustc::session::Session; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::lint; +use rustc::session::Session; +use rustc::ty::subst::{InternalSubsts, SubstsRef}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc::hir::HirId; use rustc::hir::def::*; use rustc::hir::def_id::DefId; -use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc::hir::HirId; use rustc::hir::{self, Pat}; use smallvec::smallvec; use std::slice; -use syntax_pos::{Span, DUMMY_SP, MultiSpan}; +use syntax_pos::{MultiSpan, Span, DUMMY_SP}; crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { let body_id = match tcx.hir().as_local_hir_id(def_id) { @@ -100,13 +100,15 @@ impl PatCtxt<'_, '_> { ::rustc::mir::interpret::struct_error( self.tcx.at(pat_span), "could not evaluate float literal (see issue #31407)", - ).emit(); + ) + .emit(); } PatternError::NonConstPath(span) => { ::rustc::mir::interpret::struct_error( self.tcx.at(span), "runtime values cannot be referenced in patterns", - ).emit(); + ) + .emit(); } } } @@ -123,12 +125,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { check_legality_of_bindings_in_at_patterns(self, pat); } - fn check_match( - &mut self, - scrut: &hir::Expr, - arms: &'tcx [hir::Arm], - source: hir::MatchSource - ) { + fn check_match(&mut self, scrut: &hir::Expr, arms: &'tcx [hir::Arm], source: hir::MatchSource) { for arm in arms { // First, check legality of move bindings. self.check_patterns(arm.guard.is_some(), &arm.pat); @@ -141,31 +138,41 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { let mut have_errors = false; - let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| ( - // HACK(or_patterns; Centril | dlrobertson): Remove this and - // correctly handle exhaustiveness checking for nested or-patterns. - match &arm.pat.kind { - hir::PatKind::Or(pats) => pats, - _ => std::slice::from_ref(&arm.pat), - }.iter().map(|pat| { - let mut patcx = PatCtxt::new( - self.tcx, - self.param_env.and(self.identity_substs), - self.tables - ); - patcx.include_lint_checks(); - let pattern = - cx.pattern_arena.alloc(expand_pattern(cx, patcx.lower_pattern(&pat))) as &_; - if !patcx.errors.is_empty() { - patcx.report_inlining_errors(pat.span); - have_errors = true; - } - (pattern, &**pat) - }).collect(), - arm.guard.as_ref().map(|g| match g { - hir::Guard::If(ref e) => &**e, + let inlined_arms: Vec<(Vec<_>, _)> = arms + .iter() + .map(|arm| { + ( + // HACK(or_patterns; Centril | dlrobertson): Remove this and + // correctly handle exhaustiveness checking for nested or-patterns. + match &arm.pat.kind { + hir::PatKind::Or(pats) => pats, + _ => std::slice::from_ref(&arm.pat), + } + .iter() + .map(|pat| { + let mut patcx = PatCtxt::new( + self.tcx, + self.param_env.and(self.identity_substs), + self.tables, + ); + patcx.include_lint_checks(); + let pattern = cx + .pattern_arena + .alloc(expand_pattern(cx, patcx.lower_pattern(&pat))) + as &_; + if !patcx.errors.is_empty() { + patcx.report_inlining_errors(pat.span); + have_errors = true; + } + (pattern, &**pat) + }) + .collect(), + arm.guard.as_ref().map(|g| match g { + hir::Guard::If(ref e) => &**e, + }), + ) }) - )).collect(); + .collect(); // Bail out early if inlining failed. if have_errors { @@ -191,17 +198,16 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { def_span = self.tcx.hir().span_if_local(def.did); if def.variants.len() < 4 && !def.variants.is_empty() { // keep around to point at the definition of non-covered variants - missing_variants = def.variants.iter() - .map(|variant| variant.ident) - .collect(); + missing_variants = + def.variants.iter().map(|variant| variant.ident).collect(); } let is_non_exhaustive_and_non_local = def.is_variant_list_non_exhaustive() && !def.did.is_local(); !(is_non_exhaustive_and_non_local) && def.variants.is_empty() - }, - _ => false + } + _ => false, } }; if !scrutinee_is_uninhabited { @@ -209,18 +215,25 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { let mut err = create_e0004( self.tcx.sess, scrut.span, - format!("non-exhaustive patterns: {}", match missing_variants.len() { - 0 => format!("type `{}` is non-empty", pat_ty), - 1 => format!( - "pattern `{}` of type `{}` is not handled", - missing_variants[0].name, - pat_ty, - ), - _ => format!("multiple patterns of type `{}` are not handled", pat_ty), - }), + format!( + "non-exhaustive patterns: {}", + match missing_variants.len() { + 0 => format!("type `{}` is non-empty", pat_ty), + 1 => format!( + "pattern `{}` of type `{}` is not handled", + missing_variants[0].name, pat_ty, + ), + _ => format!( + "multiple patterns of type `{}` are not handled", + pat_ty + ), + } + ), + ); + err.help( + "ensure that all possible cases are being handled, \ + possibly by adding wildcards or more match arms", ); - err.help("ensure that all possible cases are being handled, \ - possibly by adding wildcards or more match arms"); if let Some(sp) = def_span { err.span_label(sp, format!("`{}` defined here", pat_ty)); } @@ -248,16 +261,13 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str, sp: Option) { let module = self.tcx.hir().get_module_parent(pat.hir_id); MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { - let mut patcx = PatCtxt::new(self.tcx, - self.param_env.and(self.identity_substs), - self.tables); + let mut patcx = + PatCtxt::new(self.tcx, self.param_env.and(self.identity_substs), self.tables); patcx.include_lint_checks(); let pattern = patcx.lower_pattern(pat); let pattern_ty = pattern.ty; let pattern = expand_pattern(cx, pattern); - let pats: Matrix<'_, '_> = vec![smallvec![ - &pattern - ]].into_iter().collect(); + let pats: Matrix<'_, '_> = vec![smallvec![&pattern]].into_iter().collect(); let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) { Ok(_) => return, @@ -266,9 +276,12 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { let joined_patterns = joined_uncovered_patterns(&witnesses); let mut err = struct_span_err!( - self.tcx.sess, pat.span, E0005, + self.tcx.sess, + pat.span, + E0005, "refutable pattern in {}: {} not covered", - origin, joined_patterns + origin, + joined_patterns ); let suggest_if_let = match &pat.kind { hir::PatKind::Path(hir::QPath::Resolved(None, path)) @@ -287,8 +300,10 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { }; if let (Some(span), true) = (sp, suggest_if_let) { - err.note("`let` bindings require an \"irrefutable pattern\", like a `struct` or \ - an `enum` with only one variant"); + err.note( + "`let` bindings require an \"irrefutable pattern\", like a `struct` or \ + an `enum` with only one variant", + ); if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { err.span_suggestion( span, @@ -297,8 +312,10 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { Applicability::HasPlaceholders, ); } - err.note("for more information, visit \ - https://doc.rust-lang.org/book/ch18-02-refutability.html"); + err.note( + "for more information, visit \ + https://doc.rust-lang.org/book/ch18-02-refutability.html", + ); } adt_defined_here(cx, &mut err, pattern_ty, &witnesses); @@ -311,11 +328,10 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { /// This caused an irrefutable match failure in e.g. `let`. fn const_not_var(err: &mut DiagnosticBuilder<'_>, tcx: TyCtxt<'_>, pat: &Pat, path: &hir::Path) { let descr = path.res.descr(); - err.span_label(pat.span, format!( - "interpreted as {} {} pattern, not a new variable", - path.res.article(), - descr, - )); + err.span_label( + pat.span, + format!("interpreted as {} {} pattern, not a new variable", path.res.article(), descr,), + ); err.span_suggestion( pat.span, @@ -342,19 +358,26 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa } let pat_ty = cx.tables.pat_ty(p); if let ty::Adt(edef, _) = pat_ty.kind { - if edef.is_enum() && edef.variants.iter().any(|variant| { - variant.ident == ident && variant.ctor_kind == CtorKind::Const - }) { + if edef.is_enum() + && edef.variants.iter().any(|variant| { + variant.ident == ident && variant.ctor_kind == CtorKind::Const + }) + { let ty_path = cx.tcx.def_path_str(edef.did); - let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, + let mut err = struct_span_warn!( + cx.tcx.sess, + p.span, + E0170, "pattern binding `{}` is named the same as one \ - of the variants of the type `{}`", - ident, ty_path); + of the variants of the type `{}`", + ident, + ty_path + ); err.span_suggestion( p.span, "to match on the variant, qualify the path", format!("{}::{}", ty_path, ident), - Applicability::MachineApplicable + Applicability::MachineApplicable, ); err.emit(); } @@ -373,10 +396,8 @@ fn pat_is_catchall(pat: &Pat) -> bool { hir::PatKind::Binding(.., None) => true, hir::PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s), hir::PatKind::Ref(ref s, _) => pat_is_catchall(s), - hir::PatKind::Tuple(ref v, _) => v.iter().all(|p| { - pat_is_catchall(&p) - }), - _ => false + hir::PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(&p)), + _ => false, } } @@ -395,8 +416,9 @@ fn check_arms<'tcx>( match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) { NotUseful => { match source { - hir::MatchSource::IfDesugar { .. } | - hir::MatchSource::WhileDesugar => bug!(), + hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => { + bug!() + } hir::MatchSource::IfLetDesugar { .. } => { cx.tcx.lint_hir( lint::builtin::IRREFUTABLE_LET_PATTERNS, @@ -413,9 +435,11 @@ fn check_arms<'tcx>( 0 => { cx.tcx.lint_hir( lint::builtin::UNREACHABLE_PATTERNS, - hir_pat.hir_id, pat.span, - "unreachable pattern"); - }, + hir_pat.hir_id, + pat.span, + "unreachable pattern", + ); + } // The arm with the wildcard pattern. 1 => { cx.tcx.lint_hir( @@ -424,13 +448,12 @@ fn check_arms<'tcx>( pat.span, "irrefutable while-let pattern", ); - }, + } _ => bug!(), } } - hir::MatchSource::ForLoopDesugar | - hir::MatchSource::Normal => { + hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { let mut err = cx.tcx.struct_span_lint_hir( lint::builtin::UNREACHABLE_PATTERNS, hir_pat.hir_id, @@ -447,12 +470,11 @@ fn check_arms<'tcx>( // Unreachable patterns in try and await expressions occur when one of // the arms are an uninhabited type. Which is OK. - hir::MatchSource::AwaitDesugar | - hir::MatchSource::TryDesugar => {} + hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {} } } Useful => (), - UsefulWithWitness(_) => bug!() + UsefulWithWitness(_) => bug!(), } if guard.is_none() { seen.push(v); @@ -496,14 +518,15 @@ fn check_exhaustive<'tcx>( let joined_patterns = joined_uncovered_patterns(&witnesses); let mut err = create_e0004( - cx.tcx.sess, sp, + cx.tcx.sess, + sp, format!("non-exhaustive patterns: {} not covered", joined_patterns), ); err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); adt_defined_here(cx, &mut err, scrut_ty, &witnesses); err.help( "ensure that all possible cases are being handled, \ - possibly by adding wildcards or more match arms" + possibly by adding wildcards or more match arms", ) .emit(); } @@ -556,7 +579,7 @@ fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec // Don't point at variants that have already been covered due to other patterns to avoid // visual clutter. for pattern in patterns { - use PatKind::{AscribeUserType, Deref, Variant, Or, Leaf}; + use PatKind::{AscribeUserType, Deref, Leaf, Or, Variant}; match &*pattern.kind { AscribeUserType { subpattern, .. } | Deref { subpattern } => { covered.extend(maybe_point_at_variant(ty, slice::from_ref(&subpattern))); @@ -568,13 +591,15 @@ fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec } covered.push(sp); - let pats = subpatterns.iter() + let pats = subpatterns + .iter() .map(|field_pattern| field_pattern.pattern.clone()) .collect::>(); covered.extend(maybe_point_at_variant(ty, &pats)); } Leaf { subpatterns } => { - let pats = subpatterns.iter() + let pats = subpatterns + .iter() .map(|field_pattern| field_pattern.pattern.clone()) .collect::>(); covered.extend(maybe_point_at_variant(ty, &pats)); @@ -659,7 +684,7 @@ fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pa struct AtBindingPatternVisitor<'a, 'b, 'tcx> { cx: &'a MatchVisitor<'b, 'tcx>, - bindings_allowed: bool + bindings_allowed: bool, } impl<'v> Visitor<'v> for AtBindingPatternVisitor<'_, '_, '_> { @@ -671,10 +696,14 @@ impl<'v> Visitor<'v> for AtBindingPatternVisitor<'_, '_, '_> { match pat.kind { hir::PatKind::Binding(.., ref subpat) => { if !self.bindings_allowed { - struct_span_err!(self.cx.tcx.sess, pat.span, E0303, - "pattern bindings are not allowed after an `@`") - .span_label(pat.span, "not allowed after `@`") - .emit(); + struct_span_err!( + self.cx.tcx.sess, + pat.span, + E0303, + "pattern bindings are not allowed after an `@`" + ) + .span_label(pat.span, "not allowed after `@`") + .emit(); } if subpat.is_some() {