@@ -140,70 +140,45 @@ fn check_opt_like<'a>(
140140 ty : Ty < ' a > ,
141141 els : Option < & Expr < ' _ > > ,
142142) {
143- // list of candidate `Enum`s we know will never get any more members
144- let candidates = & [
145- ( & paths:: COW , "Borrowed" ) ,
146- ( & paths:: COW , "Cow::Borrowed" ) ,
147- ( & paths:: COW , "Cow::Owned" ) ,
148- ( & paths:: COW , "Owned" ) ,
149- ( & paths:: OPTION , "None" ) ,
150- ( & paths:: RESULT , "Err" ) ,
151- ( & paths:: RESULT , "Ok" ) ,
152- ] ;
153-
154- // We want to suggest to exclude an arm that contains only wildcards or forms the exhaustive
155- // match with the second branch, without enum variants in matches.
156- if !contains_only_wilds ( arms[ 1 ] . pat ) && !form_exhaustive_matches ( arms[ 0 ] . pat , arms[ 1 ] . pat ) {
157- return ;
143+ // We don't want to lint if the second arm contains an enum which could
144+ // have more variants in the future.
145+ if form_exhaustive_matches ( cx, ty, arms[ 0 ] . pat , arms[ 1 ] . pat ) {
146+ report_single_pattern ( cx, ex, arms, expr, els) ;
158147 }
148+ }
159149
150+ /// Returns `true` if all of the types in the pattern are enums which we know
151+ /// won't be expanded in the future
152+ fn pat_in_candidate_enum < ' a > ( cx : & LateContext < ' a > , ty : Ty < ' a > , pat : & Pat < ' _ > ) -> bool {
160153 let mut paths_and_types = Vec :: new ( ) ;
161- if ! collect_pat_paths ( & mut paths_and_types, cx, arms [ 1 ] . pat , ty) {
162- return ;
163- }
154+ collect_pat_paths ( & mut paths_and_types, cx, pat, ty) ;
155+ paths_and_types . iter ( ) . all ( |ty| in_candidate_enum ( cx , * ty ) )
156+ }
164157
165- let in_candidate_enum = |path_info : & ( String , Ty < ' _ > ) | -> bool {
166- let ( path, ty) = path_info;
167- for & ( ty_path, pat_path) in candidates {
168- if path == pat_path && match_type ( cx, * ty, ty_path) {
169- return true ;
170- }
158+ /// Returns `true` if the given type is an enum we know won't be expanded in the future
159+ fn in_candidate_enum < ' a > ( cx : & LateContext < ' a > , ty : Ty < ' _ > ) -> bool {
160+ // list of candidate `Enum`s we know will never get any more members
161+ let candidates = [ & paths:: COW , & paths:: OPTION , & paths:: RESULT ] ;
162+
163+ for candidate_ty in candidates {
164+ if match_type ( cx, ty, candidate_ty) {
165+ return true ;
171166 }
172- false
173- } ;
174- if paths_and_types. iter ( ) . all ( in_candidate_enum) {
175- report_single_pattern ( cx, ex, arms, expr, els) ;
176167 }
168+ false
177169}
178170
179- /// Collects paths and their types from the given patterns. Returns true if the given pattern could
180- /// be simplified, false otherwise.
181- fn collect_pat_paths < ' a > ( acc : & mut Vec < ( String , Ty < ' a > ) > , cx : & LateContext < ' a > , pat : & Pat < ' _ > , ty : Ty < ' a > ) -> bool {
171+ /// Collects types from the given pattern
172+ fn collect_pat_paths < ' a > ( acc : & mut Vec < Ty < ' a > > , cx : & LateContext < ' a > , pat : & Pat < ' _ > , ty : Ty < ' a > ) {
182173 match pat. kind {
183- PatKind :: Wild => true ,
184- PatKind :: Tuple ( inner, _) => inner. iter ( ) . all ( |p| {
174+ PatKind :: Tuple ( inner, _) => inner. iter ( ) . for_each ( |p| {
185175 let p_ty = cx. typeck_results ( ) . pat_ty ( p) ;
186- collect_pat_paths ( acc, cx, p, p_ty)
176+ collect_pat_paths ( acc, cx, p, p_ty) ;
187177 } ) ,
188- PatKind :: TupleStruct ( ref path, ..) => {
189- let path = rustc_hir_pretty:: to_string ( rustc_hir_pretty:: NO_ANN , |s| {
190- s. print_qpath ( path, false ) ;
191- } ) ;
192- acc. push ( ( path, ty) ) ;
193- true
194- } ,
195- PatKind :: Binding ( BindingAnnotation :: Unannotated , .., ident, None ) => {
196- acc. push ( ( ident. to_string ( ) , ty) ) ;
197- true
178+ PatKind :: TupleStruct ( ..) | PatKind :: Binding ( BindingAnnotation :: Unannotated , .., None ) | PatKind :: Path ( _) => {
179+ acc. push ( ty) ;
198180 } ,
199- PatKind :: Path ( ref path) => {
200- let path = rustc_hir_pretty:: to_string ( rustc_hir_pretty:: NO_ANN , |s| {
201- s. print_qpath ( path, false ) ;
202- } ) ;
203- acc. push ( ( path, ty) ) ;
204- true
205- } ,
206- _ => false ,
181+ _ => { } ,
207182 }
208183}
209184
@@ -218,7 +193,7 @@ fn contains_only_wilds(pat: &Pat<'_>) -> bool {
218193
219194/// Returns true if the given patterns forms only exhaustive matches that don't contain enum
220195/// patterns without a wildcard.
221- fn form_exhaustive_matches ( left : & Pat < ' _ > , right : & Pat < ' _ > ) -> bool {
196+ fn form_exhaustive_matches < ' a > ( cx : & LateContext < ' a > , ty : Ty < ' a > , left : & Pat < ' _ > , right : & Pat < ' _ > ) -> bool {
222197 match ( & left. kind , & right. kind ) {
223198 ( PatKind :: Wild , _) | ( _, PatKind :: Wild ) => true ,
224199 ( PatKind :: Tuple ( left_in, left_pos) , PatKind :: Tuple ( right_in, right_pos) ) => {
@@ -264,6 +239,10 @@ fn form_exhaustive_matches(left: &Pat<'_>, right: &Pat<'_>) -> bool {
264239 }
265240 true
266241 } ,
242+ ( PatKind :: TupleStruct ( ..) , PatKind :: Path ( _) ) => pat_in_candidate_enum ( cx, ty, right) ,
243+ ( PatKind :: TupleStruct ( ..) , PatKind :: TupleStruct ( _, inner, _) ) => {
244+ pat_in_candidate_enum ( cx, ty, right) && inner. iter ( ) . all ( contains_only_wilds)
245+ } ,
267246 _ => false ,
268247 }
269248}
0 commit comments