@@ -312,20 +312,16 @@ impl PatStack {
312312 Self ( v)
313313 }
314314
315- fn is_empty ( & self ) -> bool {
316- self . 0 . is_empty ( )
317- }
318-
319- fn head ( & self ) -> PatIdOrWild {
320- self . 0 [ 0 ]
321- }
322-
323315 fn get_head ( & self ) -> Option < PatIdOrWild > {
324316 self . 0 . first ( ) . copied ( )
325317 }
326318
319+ fn tail ( & self ) -> & [ PatIdOrWild ] {
320+ self . 0 . get ( 1 ..) . unwrap_or ( & [ ] )
321+ }
322+
327323 fn to_tail ( & self ) -> PatStack {
328- Self :: from_slice ( & self . 0 [ 1 .. ] )
324+ Self :: from_slice ( self . tail ( ) )
329325 }
330326
331327 fn replace_head_with < I , T > ( & self , pats : I ) -> PatStack
@@ -347,7 +343,7 @@ impl PatStack {
347343 ///
348344 /// See the module docs and the associated documentation in rustc for details.
349345 fn specialize_wildcard ( & self , cx : & MatchCheckCtx ) -> Option < PatStack > {
350- if matches ! ( self . head ( ) . as_pat( cx) , Pat :: Wild ) {
346+ if matches ! ( self . get_head ( ) ? . as_pat( cx) , Pat :: Wild ) {
351347 Some ( self . to_tail ( ) )
352348 } else {
353349 None
@@ -362,11 +358,12 @@ impl PatStack {
362358 cx : & MatchCheckCtx ,
363359 constructor : & Constructor ,
364360 ) -> MatchCheckResult < Option < PatStack > > {
365- if self . is_empty ( ) {
366- return Ok ( None ) ;
367- }
361+ let head = match self . get_head ( ) {
362+ Some ( head) => head,
363+ None => return Ok ( None ) ,
364+ } ;
368365
369- let head_pat = self . head ( ) . as_pat ( cx) ;
366+ let head_pat = head. as_pat ( cx) ;
370367 let result = match ( head_pat, constructor) {
371368 ( Pat :: Tuple { args : ref pat_ids, ellipsis } , Constructor :: Tuple { arity : _ } ) => {
372369 if ellipsis. is_some ( ) {
@@ -394,7 +391,7 @@ impl PatStack {
394391 ( Pat :: Wild , constructor) => Some ( self . expand_wildcard ( cx, constructor) ?) ,
395392 ( Pat :: Path ( _) , Constructor :: Enum ( constructor) ) => {
396393 // unit enum variants become `Pat::Path`
397- let pat_id = self . head ( ) . as_id ( ) . expect ( "we know this isn't a wild" ) ;
394+ let pat_id = head. as_id ( ) . expect ( "we know this isn't a wild" ) ;
398395 if !enum_variant_matches ( cx, pat_id, * constructor) {
399396 None
400397 } else {
@@ -405,7 +402,7 @@ impl PatStack {
405402 Pat :: TupleStruct { args : ref pat_ids, ellipsis, .. } ,
406403 Constructor :: Enum ( enum_constructor) ,
407404 ) => {
408- let pat_id = self . head ( ) . as_id ( ) . expect ( "we know this isn't a wild" ) ;
405+ let pat_id = head. as_id ( ) . expect ( "we know this isn't a wild" ) ;
409406 if !enum_variant_matches ( cx, pat_id, * enum_constructor) {
410407 None
411408 } else {
@@ -445,7 +442,7 @@ impl PatStack {
445442 }
446443 }
447444 ( Pat :: Record { args : ref arg_patterns, .. } , Constructor :: Enum ( e) ) => {
448- let pat_id = self . head ( ) . as_id ( ) . expect ( "we know this isn't a wild" ) ;
445+ let pat_id = head. as_id ( ) . expect ( "we know this isn't a wild" ) ;
449446 if !enum_variant_matches ( cx, pat_id, * e) {
450447 None
451448 } else {
@@ -491,7 +488,7 @@ impl PatStack {
491488 ) -> MatchCheckResult < PatStack > {
492489 assert_eq ! (
493490 Pat :: Wild ,
494- self . head ( ) . as_pat( cx) ,
491+ self . get_head ( ) . expect ( "expand_wildcard called on empty PatStack" ) . as_pat( cx) ,
495492 "expand_wildcard must only be called on PatStack with wild at head" ,
496493 ) ;
497494
@@ -509,7 +506,6 @@ impl PatStack {
509506 }
510507}
511508
512- #[ derive( Debug ) ]
513509/// A collection of PatStack.
514510///
515511/// This type is modeled from the struct of the same name in `rustc`.
@@ -623,13 +619,16 @@ pub(crate) fn is_useful(
623619 _ => ( ) ,
624620 }
625621
626- if v. is_empty ( ) {
627- let result = if matrix. is_empty ( ) { Usefulness :: Useful } else { Usefulness :: NotUseful } ;
622+ let head = match v. get_head ( ) {
623+ Some ( head) => head,
624+ None => {
625+ let result = if matrix. is_empty ( ) { Usefulness :: Useful } else { Usefulness :: NotUseful } ;
628626
629- return Ok ( result) ;
630- }
627+ return Ok ( result) ;
628+ }
629+ } ;
631630
632- if let Pat :: Or ( pat_ids) = v . head ( ) . as_pat ( cx) {
631+ if let Pat :: Or ( pat_ids) = head. as_pat ( cx) {
633632 let mut found_unimplemented = false ;
634633 let any_useful = pat_ids. iter ( ) . any ( |& pat_id| {
635634 let v = PatStack :: from_pattern ( pat_id) ;
@@ -653,7 +652,7 @@ pub(crate) fn is_useful(
653652 } ;
654653 }
655654
656- if let Some ( constructor) = pat_constructor ( cx, v . head ( ) ) ? {
655+ if let Some ( constructor) = pat_constructor ( cx, head) ? {
657656 let matrix = matrix. specialize_constructor ( & cx, & constructor) ?;
658657 let v = v
659658 . specialize_constructor ( & cx, & constructor) ?
@@ -854,10 +853,10 @@ mod tests {
854853 }
855854
856855 pub ( super ) fn check_no_diagnostic ( ra_fixture : & str ) {
857- let diagnostic_count =
858- TestDB :: with_single_file ( ra_fixture) . 0 . diagnostic :: < MissingMatchArms > ( ) . 1 ;
856+ let ( s , diagnostic_count) =
857+ TestDB :: with_single_file ( ra_fixture) . 0 . diagnostic :: < MissingMatchArms > ( ) ;
859858
860- assert_eq ! ( 0 , diagnostic_count, "expected no diagnostic, found one" ) ;
859+ assert_eq ! ( 0 , diagnostic_count, "expected no diagnostic, found one: {}" , s ) ;
861860 }
862861
863862 #[ test]
@@ -2014,6 +2013,28 @@ mod tests {
20142013 " ,
20152014 ) ;
20162015 }
2016+
2017+ #[ test]
2018+ fn or_pattern_panic_2 ( ) {
2019+ // FIXME: This is a false positive, but the code used to cause a panic in the match checker,
2020+ // so this acts as a regression test for that.
2021+ check_diagnostic (
2022+ r"
2023+ pub enum Category {
2024+ Infinity,
2025+ Zero,
2026+ }
2027+
2028+ fn panic(a: Category, b: Category) {
2029+ match (a, b) {
2030+ (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => {}
2031+
2032+ (Category::Infinity | Category::Zero, _) => {}
2033+ }
2034+ }
2035+ " ,
2036+ ) ;
2037+ }
20172038}
20182039
20192040#[ cfg( test) ]
0 commit comments