1
+ #![ allow( dead_code, unreachable_pub) ]
1
2
use rustc_pattern_analysis:: constructor:: {
2
3
Constructor , ConstructorSet , IntRange , MaybeInfiniteInt , RangeEnd , VariantVisibility ,
3
4
} ;
@@ -22,8 +23,10 @@ fn init_tracing() {
22
23
. try_init ( ) ;
23
24
}
24
25
26
+ pub ( super ) const UNIT : Ty = Ty :: Tuple ( & [ ] ) ;
27
+ pub ( super ) const NEVER : Ty = Ty :: Enum ( & [ ] ) ;
28
+
25
29
/// A simple set of types.
26
- #[ allow( dead_code) ]
27
30
#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
28
31
pub ( super ) enum Ty {
29
32
/// Booleans
@@ -38,6 +41,8 @@ pub(super) enum Ty {
38
41
BigStruct { arity : usize , ty : & ' static Ty } ,
39
42
/// A enum with `arity` variants of type `ty`.
40
43
BigEnum { arity : usize , ty : & ' static Ty } ,
44
+ /// Like `Enum` but non-exhaustive.
45
+ NonExhaustiveEnum ( & ' static [ Ty ] ) ,
41
46
}
42
47
43
48
/// The important logic.
@@ -47,7 +52,7 @@ impl Ty {
47
52
match ( ctor, * self ) {
48
53
( Struct , Ty :: Tuple ( tys) ) => tys. iter ( ) . copied ( ) . collect ( ) ,
49
54
( Struct , Ty :: BigStruct { arity, ty } ) => ( 0 ..arity) . map ( |_| * ty) . collect ( ) ,
50
- ( Variant ( i) , Ty :: Enum ( tys) ) => vec ! [ tys[ * i] ] ,
55
+ ( Variant ( i) , Ty :: Enum ( tys) | Ty :: NonExhaustiveEnum ( tys ) ) => vec ! [ tys[ * i] ] ,
51
56
( Variant ( _) , Ty :: BigEnum { ty, .. } ) => vec ! [ * ty] ,
52
57
( Bool ( ..) | IntRange ( ..) | NonExhaustive | Missing | Wildcard , _) => vec ! [ ] ,
53
58
_ => panic ! ( "Unexpected ctor {ctor:?} for type {self:?}" ) ,
@@ -61,6 +66,7 @@ impl Ty {
61
66
Ty :: Enum ( tys) => tys. iter ( ) . all ( |ty| ty. is_empty ( ) ) ,
62
67
Ty :: BigStruct { arity, ty } => arity != 0 && ty. is_empty ( ) ,
63
68
Ty :: BigEnum { arity, ty } => arity == 0 || ty. is_empty ( ) ,
69
+ Ty :: NonExhaustiveEnum ( ..) => false ,
64
70
}
65
71
}
66
72
@@ -90,6 +96,19 @@ impl Ty {
90
96
. collect ( ) ,
91
97
non_exhaustive : false ,
92
98
} ,
99
+ Ty :: NonExhaustiveEnum ( tys) => ConstructorSet :: Variants {
100
+ variants : tys
101
+ . iter ( )
102
+ . map ( |ty| {
103
+ if ty. is_empty ( ) {
104
+ VariantVisibility :: Empty
105
+ } else {
106
+ VariantVisibility :: Visible
107
+ }
108
+ } )
109
+ . collect ( ) ,
110
+ non_exhaustive : true ,
111
+ } ,
93
112
Ty :: BigEnum { arity : 0 , .. } => ConstructorSet :: NoConstructors ,
94
113
Ty :: BigEnum { arity, ty } => {
95
114
let vis = if ty. is_empty ( ) {
@@ -113,7 +132,9 @@ impl Ty {
113
132
match ( * self , ctor) {
114
133
( Ty :: Tuple ( ..) , _) => Ok ( ( ) ) ,
115
134
( Ty :: BigStruct { .. } , _) => write ! ( f, "BigStruct" ) ,
116
- ( Ty :: Enum ( ..) , Constructor :: Variant ( i) ) => write ! ( f, "Enum::Variant{i}" ) ,
135
+ ( Ty :: Enum ( ..) | Ty :: NonExhaustiveEnum ( ..) , Constructor :: Variant ( i) ) => {
136
+ write ! ( f, "Enum::Variant{i}" )
137
+ }
117
138
( Ty :: BigEnum { .. } , Constructor :: Variant ( i) ) => write ! ( f, "BigEnum::Variant{i}" ) ,
118
139
_ => write ! ( f, "{:?}::{:?}" , self , ctor) ,
119
140
}
@@ -126,10 +147,11 @@ pub(super) fn compute_match_usefulness<'p>(
126
147
ty : Ty ,
127
148
scrut_validity : PlaceValidity ,
128
149
complexity_limit : usize ,
150
+ exhaustive_witnesses : bool ,
129
151
) -> Result < UsefulnessReport < ' p , Cx > , ( ) > {
130
152
init_tracing ( ) ;
131
153
rustc_pattern_analysis:: usefulness:: compute_match_usefulness (
132
- & Cx ,
154
+ & Cx { exhaustive_witnesses } ,
133
155
arms,
134
156
ty,
135
157
scrut_validity,
@@ -138,7 +160,9 @@ pub(super) fn compute_match_usefulness<'p>(
138
160
}
139
161
140
162
#[ derive( Debug ) ]
141
- pub ( super ) struct Cx ;
163
+ pub ( super ) struct Cx {
164
+ exhaustive_witnesses : bool ,
165
+ }
142
166
143
167
/// The context for pattern analysis. Forwards anything interesting to `Ty` methods.
144
168
impl PatCx for Cx {
@@ -153,6 +177,10 @@ impl PatCx for Cx {
153
177
false
154
178
}
155
179
180
+ fn exhaustive_witnesses ( & self ) -> bool {
181
+ self . exhaustive_witnesses
182
+ }
183
+
156
184
fn ctor_arity ( & self , ctor : & Constructor < Self > , ty : & Self :: Ty ) -> usize {
157
185
ty. sub_tys ( ctor) . len ( )
158
186
}
@@ -219,16 +247,18 @@ macro_rules! pats {
219
247
// Entrypoint
220
248
// Parse `type; ..`
221
249
( $ty: expr; $( $rest: tt) * ) => { {
222
- #[ allow( unused_imports ) ]
250
+ #[ allow( unused ) ]
223
251
use rustc_pattern_analysis:: {
224
252
constructor:: { Constructor , IntRange , MaybeInfiniteInt , RangeEnd } ,
225
- pat:: DeconstructedPat ,
253
+ pat:: { DeconstructedPat , IndexedPat } ,
226
254
} ;
227
255
let ty = $ty;
228
256
// The heart of the macro is designed to push `IndexedPat`s into a `Vec`, so we work around
229
257
// that.
258
+ #[ allow( unused) ]
230
259
let sub_tys = :: std:: iter:: repeat( & ty) ;
231
- let mut vec = Vec :: new( ) ;
260
+ #[ allow( unused) ]
261
+ let mut vec: Vec <IndexedPat <_>> = Vec :: new( ) ;
232
262
pats!( @ctor( vec: vec, sub_tys: sub_tys, idx: 0 ) $( $rest) * ) ;
233
263
vec. into_iter( ) . map( |ipat| ipat. pat) . collect:: <Vec <_>>( )
234
264
} } ;
@@ -263,6 +293,8 @@ macro_rules! pats {
263
293
let ctor = Constructor :: Wildcard ;
264
294
pats!( @pat( $( $args) * , ctor: ctor) $( $rest) * )
265
295
} } ;
296
+ // Nothing
297
+ ( @ctor( $( $args: tt) * ) ) => { } ;
266
298
267
299
// Integers and int ranges
268
300
( @ctor( $( $args: tt) * ) $( $start: literal) ?..$end: literal $( $rest: tt) * ) => { {
0 commit comments