@@ -13,7 +13,7 @@ use rustc_hir_analysis::astconv::AstConv;
1313use rustc_infer:: infer:: { self , TyCtxtInferExt } ;
1414use rustc_infer:: traits:: { self , StatementAsExpression } ;
1515use rustc_middle:: lint:: in_external_macro;
16- use rustc_middle:: ty:: { self , Binder , IsSuggestable , ToPredicate , Ty } ;
16+ use rustc_middle:: ty:: { self , Binder , DefIdTree , IsSuggestable , ToPredicate , Ty } ;
1717use rustc_session:: errors:: ExprParenthesesNeeded ;
1818use rustc_span:: symbol:: sym;
1919use rustc_span:: Span ;
@@ -1116,6 +1116,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11161116 false
11171117 }
11181118
1119+ /// When expecting a `bool` and finding an `Option`, suggests using `let Some(..)` or `.is_some()`
1120+ pub ( crate ) fn suggest_option_to_bool (
1121+ & self ,
1122+ diag : & mut Diagnostic ,
1123+ expr : & hir:: Expr < ' _ > ,
1124+ expr_ty : Ty < ' tcx > ,
1125+ expected_ty : Ty < ' tcx > ,
1126+ ) -> bool {
1127+ if !expected_ty. is_bool ( ) {
1128+ return false ;
1129+ }
1130+
1131+ let ty:: Adt ( def, _) = expr_ty. peel_refs ( ) . kind ( ) else { return false ; } ;
1132+ if !self . tcx . is_diagnostic_item ( sym:: Option , def. did ( ) ) {
1133+ return false ;
1134+ }
1135+
1136+ let hir = self . tcx . hir ( ) ;
1137+ let cond_parent = hir. parent_iter ( expr. hir_id ) . skip_while ( |( _, node) | {
1138+ matches ! ( node, hir:: Node :: Expr ( hir:: Expr { kind: hir:: ExprKind :: Binary ( op, _, _) , .. } ) if op. node == hir:: BinOpKind :: And )
1139+ } ) . next ( ) ;
1140+ // Don't suggest:
1141+ // `let Some(_) = a.is_some() && b`
1142+ // ++++++++++
1143+ // since the user probably just misunderstood how `let else`
1144+ // and `&&` work together.
1145+ if let Some ( ( _, hir:: Node :: Local ( local) ) ) = cond_parent
1146+ && let hir:: PatKind :: Path ( qpath) | hir:: PatKind :: TupleStruct ( qpath, _, _) = & local. pat . kind
1147+ && let hir:: QPath :: Resolved ( None , path) = qpath
1148+ && let Some ( did) = path. res . opt_def_id ( )
1149+ . and_then ( |did| self . tcx . opt_parent ( did) )
1150+ . and_then ( |did| self . tcx . opt_parent ( did) )
1151+ && self . tcx . is_diagnostic_item ( sym:: Option , did)
1152+ {
1153+ return false ;
1154+ }
1155+
1156+ diag. span_suggestion (
1157+ expr. span . shrink_to_hi ( ) ,
1158+ "use `Option::is_some` to test if the `Option` has a value" ,
1159+ ".is_some()" ,
1160+ Applicability :: MachineApplicable ,
1161+ ) ;
1162+
1163+ true
1164+ }
1165+
11191166 /// Suggest wrapping the block in square brackets instead of curly braces
11201167 /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
11211168 pub ( crate ) fn suggest_block_to_brackets (
0 commit comments