11use super :: _match:: Usefulness :: * ;
22use super :: _match:: WitnessPreference :: * ;
33use super :: _match:: { expand_pattern, is_useful, MatchCheckCtxt , Matrix , PatStack } ;
4-
54use super :: { PatCtxt , PatKind , PatternError } ;
65
6+ use arena:: TypedArena ;
77use rustc_ast:: ast:: Mutability ;
88use rustc_errors:: { error_code, struct_span_err, Applicability , DiagnosticBuilder } ;
99use rustc_hir as hir;
@@ -17,7 +17,6 @@ use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERN
1717use rustc_session:: parse:: feature_err;
1818use rustc_session:: Session ;
1919use rustc_span:: { sym, Span } ;
20-
2120use std:: slice;
2221
2322crate fn check_match ( tcx : TyCtxt < ' _ > , def_id : DefId ) {
@@ -26,8 +25,12 @@ crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
2625 Some ( id) => tcx. hir ( ) . body_owned_by ( tcx. hir ( ) . as_local_hir_id ( id) ) ,
2726 } ;
2827
29- let mut visitor =
30- MatchVisitor { tcx, tables : tcx. body_tables ( body_id) , param_env : tcx. param_env ( def_id) } ;
28+ let mut visitor = MatchVisitor {
29+ tcx,
30+ tables : tcx. body_tables ( body_id) ,
31+ param_env : tcx. param_env ( def_id) ,
32+ pattern_arena : TypedArena :: default ( ) ,
33+ } ;
3134 visitor. visit_body ( tcx. hir ( ) . body ( body_id) ) ;
3235}
3336
@@ -39,6 +42,7 @@ struct MatchVisitor<'a, 'tcx> {
3942 tcx : TyCtxt < ' tcx > ,
4043 tables : & ' a ty:: TypeckTables < ' tcx > ,
4144 param_env : ty:: ParamEnv < ' tcx > ,
45+ pattern_arena : TypedArena < super :: Pat < ' tcx > > ,
4246}
4347
4448impl < ' tcx > Visitor < ' tcx > for MatchVisitor < ' _ , ' tcx > {
@@ -143,9 +147,13 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
143147 ( pattern, pattern_ty)
144148 }
145149
146- fn check_in_cx ( & self , hir_id : HirId , f : impl FnOnce ( MatchCheckCtxt < ' _ , ' tcx > ) ) {
147- let module = self . tcx . parent_module ( hir_id) ;
148- MatchCheckCtxt :: create_and_enter ( self . tcx , self . param_env , module. to_def_id ( ) , |cx| f ( cx) ) ;
150+ fn new_cx ( & self , hir_id : HirId ) -> MatchCheckCtxt < ' _ , ' tcx > {
151+ MatchCheckCtxt {
152+ tcx : self . tcx ,
153+ param_env : self . param_env ,
154+ module : self . tcx . parent_module ( hir_id) . to_def_id ( ) ,
155+ pattern_arena : & self . pattern_arena ,
156+ }
149157 }
150158
151159 fn check_match (
@@ -159,91 +167,88 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
159167 self . check_patterns ( arm. guard . is_some ( ) , & arm. pat ) ;
160168 }
161169
162- self . check_in_cx ( scrut. hir_id , |ref mut cx| {
163- let mut have_errors = false ;
170+ let mut cx = self . new_cx ( scrut. hir_id ) ;
164171
165- let inlined_arms: Vec < _ > = arms
166- . iter ( )
167- . map ( |hir:: Arm { pat, guard, .. } | {
168- ( self . lower_pattern ( cx, pat, & mut have_errors) . 0 , pat. hir_id , guard. is_some ( ) )
169- } )
170- . collect ( ) ;
172+ let mut have_errors = false ;
171173
172- // Bail out early if inlining failed.
173- if have_errors {
174- return ;
175- }
174+ let inlined_arms: Vec < _ > = arms
175+ . iter ( )
176+ . map ( |hir:: Arm { pat, guard, .. } | {
177+ ( self . lower_pattern ( & mut cx, pat, & mut have_errors) . 0 , pat. hir_id , guard. is_some ( ) )
178+ } )
179+ . collect ( ) ;
180+
181+ // Bail out early if inlining failed.
182+ if have_errors {
183+ return ;
184+ }
176185
177- // Fourth, check for unreachable arms.
178- let matrix = check_arms ( cx, & inlined_arms, source) ;
186+ // Fourth, check for unreachable arms.
187+ let matrix = check_arms ( & mut cx, & inlined_arms, source) ;
179188
180- // Fifth, check if the match is exhaustive.
181- let scrut_ty = self . tables . node_type ( scrut. hir_id ) ;
182- // Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
183- // since an empty matrix can occur when there are arms, if those arms all have guards.
184- let is_empty_match = inlined_arms. is_empty ( ) ;
185- check_exhaustive ( cx, scrut_ty, scrut. span , & matrix, scrut. hir_id , is_empty_match) ;
186- } )
189+ // Fifth, check if the match is exhaustive.
190+ let scrut_ty = self . tables . node_type ( scrut. hir_id ) ;
191+ // Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
192+ // since an empty matrix can occur when there are arms, if those arms all have guards.
193+ let is_empty_match = inlined_arms. is_empty ( ) ;
194+ check_exhaustive ( & mut cx, scrut_ty, scrut. span , & matrix, scrut. hir_id , is_empty_match) ;
187195 }
188196
189197 fn check_irrefutable ( & self , pat : & ' tcx Pat < ' tcx > , origin : & str , sp : Option < Span > ) {
190- self . check_in_cx ( pat. hir_id , |ref mut cx| {
191- let ( pattern, pattern_ty) = self . lower_pattern ( cx, pat, & mut false ) ;
192- let pats: Matrix < ' _ , ' _ > = vec ! [ PatStack :: from_pattern( pattern) ] . into_iter ( ) . collect ( ) ;
193-
194- let witnesses = match check_not_useful ( cx, pattern_ty, & pats, pat. hir_id ) {
195- Ok ( _) => return ,
196- Err ( err) => err,
197- } ;
198-
199- let joined_patterns = joined_uncovered_patterns ( & witnesses) ;
200- let mut err = struct_span_err ! (
201- self . tcx. sess,
202- pat. span,
203- E0005 ,
204- "refutable pattern in {}: {} not covered" ,
205- origin,
206- joined_patterns
207- ) ;
208- let suggest_if_let = match & pat. kind {
209- hir:: PatKind :: Path ( hir:: QPath :: Resolved ( None , path) )
210- if path. segments . len ( ) == 1 && path. segments [ 0 ] . args . is_none ( ) =>
211- {
212- const_not_var ( & mut err, cx. tcx , pat, path) ;
213- false
214- }
215- _ => {
216- err. span_label (
217- pat. span ,
218- pattern_not_covered_label ( & witnesses, & joined_patterns) ,
219- ) ;
220- true
221- }
222- } ;
198+ let mut cx = self . new_cx ( pat. hir_id ) ;
223199
224- if let ( Some ( span) , true ) = ( sp, suggest_if_let) {
225- err. note (
226- "`let` bindings require an \" irrefutable pattern\" , like a `struct` or \
227- an `enum` with only one variant",
228- ) ;
229- if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
230- err. span_suggestion (
231- span,
232- "you might want to use `if let` to ignore the variant that isn't matched" ,
233- format ! ( "if {} {{ /* */ }}" , & snippet[ ..snippet. len( ) - 1 ] ) ,
234- Applicability :: HasPlaceholders ,
235- ) ;
236- }
237- err. note (
238- "for more information, visit \
239- https://doc.rust-lang.org/book/ch18-02-refutability.html",
200+ let ( pattern, pattern_ty) = self . lower_pattern ( & mut cx, pat, & mut false ) ;
201+ let pats: Matrix < ' _ , ' _ > = vec ! [ PatStack :: from_pattern( pattern) ] . into_iter ( ) . collect ( ) ;
202+
203+ let witnesses = match check_not_useful ( & mut cx, pattern_ty, & pats, pat. hir_id ) {
204+ Ok ( _) => return ,
205+ Err ( err) => err,
206+ } ;
207+
208+ let joined_patterns = joined_uncovered_patterns ( & witnesses) ;
209+ let mut err = struct_span_err ! (
210+ self . tcx. sess,
211+ pat. span,
212+ E0005 ,
213+ "refutable pattern in {}: {} not covered" ,
214+ origin,
215+ joined_patterns
216+ ) ;
217+ let suggest_if_let = match & pat. kind {
218+ hir:: PatKind :: Path ( hir:: QPath :: Resolved ( None , path) )
219+ if path. segments . len ( ) == 1 && path. segments [ 0 ] . args . is_none ( ) =>
220+ {
221+ const_not_var ( & mut err, cx. tcx , pat, path) ;
222+ false
223+ }
224+ _ => {
225+ err. span_label ( pat. span , pattern_not_covered_label ( & witnesses, & joined_patterns) ) ;
226+ true
227+ }
228+ } ;
229+
230+ if let ( Some ( span) , true ) = ( sp, suggest_if_let) {
231+ err. note (
232+ "`let` bindings require an \" irrefutable pattern\" , like a `struct` or \
233+ an `enum` with only one variant",
234+ ) ;
235+ if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
236+ err. span_suggestion (
237+ span,
238+ "you might want to use `if let` to ignore the variant that isn't matched" ,
239+ format ! ( "if {} {{ /* */ }}" , & snippet[ ..snippet. len( ) - 1 ] ) ,
240+ Applicability :: HasPlaceholders ,
240241 ) ;
241242 }
243+ err. note (
244+ "for more information, visit \
245+ https://doc.rust-lang.org/book/ch18-02-refutability.html",
246+ ) ;
247+ }
242248
243- adt_defined_here ( cx, & mut err, pattern_ty, & witnesses) ;
244- err. note ( & format ! ( "the matched value is of type `{}`" , pattern_ty) ) ;
245- err. emit ( ) ;
246- } ) ;
249+ adt_defined_here ( & mut cx, & mut err, pattern_ty, & witnesses) ;
250+ err. note ( & format ! ( "the matched value is of type `{}`" , pattern_ty) ) ;
251+ err. emit ( ) ;
247252 }
248253}
249254
0 commit comments