@@ -62,6 +62,7 @@ use rustc_span::{Span, DUMMY_SP};
6262use rustc_target:: abi:: { Integer , Size , VariantIdx } ;
6363
6464use smallvec:: { smallvec, SmallVec } ;
65+ use std:: cell:: Cell ;
6566use std:: cmp:: { self , max, min, Ordering } ;
6667use std:: fmt;
6768use std:: iter:: { once, IntoIterator } ;
@@ -1219,21 +1220,45 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12191220 }
12201221}
12211222
1222- #[ derive( Clone ) ]
1223+ /// Values and patterns can be represented as a constructor applied to some fields. This represents
1224+ /// a pattern in this form.
1225+ /// This also keeps track of whether the pattern has been foundreachable during analysis. For this
1226+ /// reason we should be careful not to clone patterns for which we care about that. Use
1227+ /// `clone_and_forget_reachability` is you're sure.
12231228pub ( crate ) struct DeconstructedPat < ' p , ' tcx > {
12241229 ctor : Constructor < ' tcx > ,
12251230 fields : Fields < ' p , ' tcx > ,
12261231 ty : Ty < ' tcx > ,
12271232 span : Span ,
1233+ reachable : Cell < bool > ,
12281234}
12291235
12301236impl < ' p , ' tcx > DeconstructedPat < ' p , ' tcx > {
12311237 pub ( super ) fn wildcard ( ty : Ty < ' tcx > ) -> Self {
1232- Self :: new ( Wildcard , Fields :: empty ( ) , ty)
1238+ Self :: new ( Wildcard , Fields :: empty ( ) , ty, DUMMY_SP )
12331239 }
12341240
1235- pub ( super ) fn new ( ctor : Constructor < ' tcx > , fields : Fields < ' p , ' tcx > , ty : Ty < ' tcx > ) -> Self {
1236- DeconstructedPat { ctor, fields, ty, span : DUMMY_SP }
1241+ pub ( super ) fn new (
1242+ ctor : Constructor < ' tcx > ,
1243+ fields : Fields < ' p , ' tcx > ,
1244+ ty : Ty < ' tcx > ,
1245+ span : Span ,
1246+ ) -> Self {
1247+ DeconstructedPat { ctor, fields, ty, span, reachable : Cell :: new ( false ) }
1248+ }
1249+
1250+ /// Construct a pattern that matches everything that starts with this constructor.
1251+ /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
1252+ /// `Some(_)`.
1253+ pub ( super ) fn wild_from_ctor ( pcx : PatCtxt < ' _ , ' p , ' tcx > , ctor : Constructor < ' tcx > ) -> Self {
1254+ let fields = Fields :: wildcards ( pcx. cx , pcx. ty , & ctor) ;
1255+ DeconstructedPat :: new ( ctor, fields, pcx. ty , DUMMY_SP )
1256+ }
1257+
1258+ /// Clone this value. This method emphasizes that cloning loses reachability information and
1259+ /// should be done carefully.
1260+ pub ( super ) fn clone_and_forget_reachability ( & self ) -> Self {
1261+ DeconstructedPat :: new ( self . ctor . clone ( ) , self . fields , self . ty , self . span )
12371262 }
12381263
12391264 pub ( crate ) fn from_pat ( cx : & MatchCheckCtxt < ' p , ' tcx > , pat : & Pat < ' tcx > ) -> Self {
@@ -1332,12 +1357,9 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
13321357 // So here, the constructor for a `"foo"` pattern is `&` (represented by
13331358 // `Single`), and has one field. That field has constructor `Str(value)` and no
13341359 // fields.
1335- let subpattern = DeconstructedPat {
1336- ctor : Str ( value) ,
1337- fields : Fields :: empty ( ) ,
1338- ty : t, // `t` is `str`, not `&str`
1339- span : pat. span ,
1340- } ;
1360+ // Note: `t` is `str`, not `&str`.
1361+ let subpattern =
1362+ DeconstructedPat :: new ( Str ( value) , Fields :: empty ( ) , t, pat. span ) ;
13411363 ctor = Single ;
13421364 fields = Fields :: singleton ( cx, subpattern)
13431365 }
@@ -1386,7 +1408,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
13861408 fields = Fields :: from_iter ( cx, pats. into_iter ( ) . map ( mkpat) ) ;
13871409 }
13881410 }
1389- DeconstructedPat { ctor, fields, ty : pat. ty , span : pat. span }
1411+ DeconstructedPat :: new ( ctor, fields, pat. ty , pat. span )
13901412 }
13911413
13921414 pub ( crate ) fn to_pat ( & self , cx : & MatchCheckCtxt < ' p , ' tcx > ) -> Pat < ' tcx > {
@@ -1475,14 +1497,6 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
14751497 Pat { ty : self . ty , span : DUMMY_SP , kind : Box :: new ( pat) }
14761498 }
14771499
1478- /// Construct a pattern that matches everything that starts with this constructor.
1479- // For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
1480- // `Some(_)`.
1481- pub ( super ) fn wild_from_ctor ( pcx : PatCtxt < ' _ , ' p , ' tcx > , ctor : Constructor < ' tcx > ) -> Self {
1482- let fields = Fields :: wildcards ( pcx. cx , pcx. ty , & ctor) ;
1483- DeconstructedPat :: new ( ctor, fields, pcx. ty )
1484- }
1485-
14861500 pub ( super ) fn is_or_pat ( & self ) -> bool {
14871501 matches ! ( self . ctor, Or )
14881502 }
@@ -1543,6 +1557,33 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
15431557 _ => self . fields . iter_patterns ( ) . collect ( ) ,
15441558 }
15451559 }
1560+
1561+ /// We keep track for each pattern if it was ever reachable during the analysis. This is used
1562+ /// with `unreachable_spans` to report unreachable subpatterns arising from or patterns.
1563+ pub ( super ) fn set_reachable ( & self ) {
1564+ self . reachable . set ( true )
1565+ }
1566+ pub ( super ) fn is_reachable ( & self ) -> bool {
1567+ self . reachable . get ( )
1568+ }
1569+
1570+ /// Report the spans of subpatterns that were not reachable, if any.
1571+ pub ( super ) fn unreachable_spans ( & self ) -> Vec < Span > {
1572+ let mut spans = Vec :: new ( ) ;
1573+ self . collect_unreachable_spans ( & mut spans) ;
1574+ spans
1575+ }
1576+
1577+ fn collect_unreachable_spans ( & self , spans : & mut Vec < Span > ) {
1578+ // We don't look at subpatterns if we already reported the whole pattern as unreachable.
1579+ if !self . is_reachable ( ) {
1580+ spans. push ( self . span ) ;
1581+ } else {
1582+ for p in self . iter_fields ( ) {
1583+ p. collect_unreachable_spans ( spans) ;
1584+ }
1585+ }
1586+ }
15461587}
15471588
15481589/// This is mostly copied from the `Pat` impl. This is best effort and not good enough for a
0 commit comments