@@ -62,6 +62,7 @@ use rustc_span::{Span, DUMMY_SP};
62
62
use rustc_target:: abi:: { Integer , Size , VariantIdx } ;
63
63
64
64
use smallvec:: { smallvec, SmallVec } ;
65
+ use std:: cell:: Cell ;
65
66
use std:: cmp:: { self , max, min, Ordering } ;
66
67
use std:: fmt;
67
68
use std:: iter:: { once, IntoIterator } ;
@@ -1219,21 +1220,45 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1219
1220
}
1220
1221
}
1221
1222
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.
1223
1228
pub ( crate ) struct DeconstructedPat < ' p , ' tcx > {
1224
1229
ctor : Constructor < ' tcx > ,
1225
1230
fields : Fields < ' p , ' tcx > ,
1226
1231
ty : Ty < ' tcx > ,
1227
1232
span : Span ,
1233
+ reachable : Cell < bool > ,
1228
1234
}
1229
1235
1230
1236
impl < ' p , ' tcx > DeconstructedPat < ' p , ' tcx > {
1231
1237
pub ( super ) fn wildcard ( ty : Ty < ' tcx > ) -> Self {
1232
- Self :: new ( Wildcard , Fields :: empty ( ) , ty)
1238
+ Self :: new ( Wildcard , Fields :: empty ( ) , ty, DUMMY_SP )
1233
1239
}
1234
1240
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 )
1237
1262
}
1238
1263
1239
1264
pub ( crate ) fn from_pat ( cx : & MatchCheckCtxt < ' p , ' tcx > , pat : & Pat < ' tcx > ) -> Self {
@@ -1332,12 +1357,9 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
1332
1357
// So here, the constructor for a `"foo"` pattern is `&` (represented by
1333
1358
// `Single`), and has one field. That field has constructor `Str(value)` and no
1334
1359
// 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 ) ;
1341
1363
ctor = Single ;
1342
1364
fields = Fields :: singleton ( cx, subpattern)
1343
1365
}
@@ -1386,7 +1408,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
1386
1408
fields = Fields :: from_iter ( cx, pats. into_iter ( ) . map ( mkpat) ) ;
1387
1409
}
1388
1410
}
1389
- DeconstructedPat { ctor, fields, ty : pat. ty , span : pat. span }
1411
+ DeconstructedPat :: new ( ctor, fields, pat. ty , pat. span )
1390
1412
}
1391
1413
1392
1414
pub ( crate ) fn to_pat ( & self , cx : & MatchCheckCtxt < ' p , ' tcx > ) -> Pat < ' tcx > {
@@ -1475,14 +1497,6 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
1475
1497
Pat { ty : self . ty , span : DUMMY_SP , kind : Box :: new ( pat) }
1476
1498
}
1477
1499
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
-
1486
1500
pub ( super ) fn is_or_pat ( & self ) -> bool {
1487
1501
matches ! ( self . ctor, Or )
1488
1502
}
@@ -1543,6 +1557,33 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
1543
1557
_ => self . fields . iter_patterns ( ) . collect ( ) ,
1544
1558
}
1545
1559
}
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
+ }
1546
1587
}
1547
1588
1548
1589
/// This is mostly copied from the `Pat` impl. This is best effort and not good enough for a
0 commit comments