@@ -17,7 +17,7 @@ use eval::{compare_const_vals};
1717
1818use rustc_const_math:: ConstInt ;
1919
20- use rustc_data_structures:: fx:: FxHashMap ;
20+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
2121use rustc_data_structures:: indexed_vec:: Idx ;
2222
2323use pattern:: { FieldPattern , Pattern , PatternKind } ;
@@ -29,6 +29,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
2929use rustc:: mir:: Field ;
3030use rustc:: util:: common:: ErrorReported ;
3131
32+ use syntax:: ast:: NodeId ;
3233use syntax_pos:: { Span , DUMMY_SP } ;
3334
3435use arena:: TypedArena ;
@@ -144,6 +145,14 @@ impl<'a, 'tcx> FromIterator<Vec<&'a Pattern<'tcx>>> for Matrix<'a, 'tcx> {
144145//NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv
145146pub struct MatchCheckCtxt < ' a , ' tcx : ' a > {
146147 pub tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
148+ /// (roughly) where in the code the match occurs. This is necessary for
149+ /// checking inhabited-ness of types because whether a type is (visibly)
150+ /// inhabited can depend on whether it was defined in the current module or
151+ /// not. eg.
152+ /// struct Foo { _private: ! }
153+ /// can not be seen to be empty outside it's module and should not
154+ /// be matchable with an empty match statement.
155+ pub node : NodeId ,
147156 /// A wild pattern with an error type - it exists to avoid having to normalize
148157 /// associated types to get field types.
149158 pub wild_pattern : & ' a Pattern < ' tcx > ,
@@ -154,6 +163,7 @@ pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
154163impl < ' a , ' tcx > MatchCheckCtxt < ' a , ' tcx > {
155164 pub fn create_and_enter < F , R > (
156165 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
166+ node : NodeId ,
157167 f : F ) -> R
158168 where F : for < ' b > FnOnce ( MatchCheckCtxt < ' b , ' tcx > ) -> R
159169 {
@@ -167,6 +177,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
167177
168178 f ( MatchCheckCtxt {
169179 tcx : tcx,
180+ node : node,
170181 wild_pattern : & wild_pattern,
171182 pattern_arena : & pattern_arena,
172183 byte_array_map : FxHashMap ( ) ,
@@ -362,9 +373,9 @@ impl<'tcx> Witness<'tcx> {
362373/// Therefore, if there is some pattern that is unmatched by `matrix`, it will
363374/// still be unmatched if the first constructor is replaced by any of the constructors
364375/// in the return value.
365- fn missing_constructors ( cx : & mut MatchCheckCtxt ,
366- matrix : & Matrix ,
367- pcx : PatternContext ) -> Vec < Constructor > {
376+ fn missing_constructors < ' a , ' tcx : ' a > ( cx : & mut MatchCheckCtxt < ' a , ' tcx > ,
377+ matrix : & Matrix ,
378+ pcx : PatternContext < ' tcx > ) -> Vec < Constructor > {
368379 let used_constructors: Vec < Constructor > =
369380 matrix. 0 . iter ( )
370381 . flat_map ( |row| pat_constructors ( cx, row[ 0 ] , pcx) . unwrap_or ( vec ! [ ] ) )
@@ -384,16 +395,46 @@ fn missing_constructors(cx: &mut MatchCheckCtxt,
384395///
385396/// but is instead bounded by the maximum fixed length of slice patterns in
386397/// the column of patterns being analyzed.
387- fn all_constructors ( _cx : & mut MatchCheckCtxt , pcx : PatternContext ) -> Vec < Constructor > {
398+ ///
399+ /// We make sure to omit constructors that are statically impossible. eg for
400+ /// Option<!> we do not include Some(_) in the returned list of constructors.
401+ fn all_constructors < ' a , ' tcx : ' a > ( cx : & mut MatchCheckCtxt < ' a , ' tcx > ,
402+ pcx : PatternContext < ' tcx > ) -> Vec < Constructor >
403+ {
388404 match pcx. ty . sty {
389405 ty:: TyBool =>
390406 [ true , false ] . iter ( ) . map ( |b| ConstantValue ( ConstVal :: Bool ( * b) ) ) . collect ( ) ,
391- ty:: TySlice ( _) =>
392- ( 0 ..pcx. max_slice_length +1 ) . map ( |length| Slice ( length) ) . collect ( ) ,
393- ty:: TyArray ( _, length) => vec ! [ Slice ( length) ] ,
394- ty:: TyAdt ( def, _) if def. is_enum ( ) && def. variants . len ( ) > 1 =>
395- def. variants . iter ( ) . map ( |v| Variant ( v. did ) ) . collect ( ) ,
396- _ => vec ! [ Single ]
407+ ty:: TySlice ( ref sub_ty) => {
408+ if sub_ty. is_uninhabited ( Some ( cx. node ) , cx. tcx ) {
409+ vec ! [ Slice ( 0 ) ]
410+ } else {
411+ ( 0 ..pcx. max_slice_length +1 ) . map ( |length| Slice ( length) ) . collect ( )
412+ }
413+ }
414+ ty:: TyArray ( ref sub_ty, length) => {
415+ if length == 0 || !sub_ty. is_uninhabited ( Some ( cx. node ) , cx. tcx ) {
416+ vec ! [ Slice ( length) ]
417+ } else {
418+ vec ! [ ]
419+ }
420+ }
421+ ty:: TyAdt ( def, substs) if def. is_enum ( ) && def. variants . len ( ) != 1 => {
422+ def. variants . iter ( ) . filter_map ( |v| {
423+ let mut visited = FxHashSet :: default ( ) ;
424+ if v. is_uninhabited_recurse ( & mut visited, Some ( cx. node ) , cx. tcx , substs, false ) {
425+ None
426+ } else {
427+ Some ( Variant ( v. did ) )
428+ }
429+ } ) . collect ( )
430+ }
431+ _ => {
432+ if pcx. ty . is_uninhabited ( Some ( cx. node ) , cx. tcx ) {
433+ vec ! [ ]
434+ } else {
435+ vec ! [ Single ]
436+ }
437+ }
397438 }
398439}
399440
0 commit comments