@@ -8,7 +8,7 @@ use crate::method::probe;
88use crate :: method:: probe:: { IsSuggestion , Mode , ProbeScope } ;
99use core:: cmp:: min;
1010use core:: iter;
11- use hir:: def_id:: { LocalDefId } ;
11+ use hir:: def_id:: LocalDefId ;
1212use rustc_ast:: util:: parser:: { ExprPrecedence , PREC_UNAMBIGUOUS } ;
1313use rustc_data_structures:: packed:: Pu128 ;
1414use rustc_errors:: { Applicability , Diag , MultiSpan } ;
@@ -1429,6 +1429,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14291429 true
14301430 }
14311431
1432+ // Suggest to change `Option<&Vec<T>>::unwrap_or(&[])` to `Option::map_or(&[], |v| v)`.
1433+ #[ instrument( level = "trace" , skip( self , err, provided_expr) ) ]
1434+ pub ( crate ) fn suggest_deref_unwrap_or (
1435+ & self ,
1436+ err : & mut Diag < ' _ > ,
1437+ error_span : Span ,
1438+ callee_ty : Option < Ty < ' tcx > > ,
1439+ call_ident : Option < Ident > ,
1440+ expected_ty : Ty < ' tcx > ,
1441+ provided_ty : Ty < ' tcx > ,
1442+ provided_expr : & Expr < ' tcx > ,
1443+ is_method : bool ,
1444+ ) {
1445+ if !is_method {
1446+ return ;
1447+ }
1448+ let Some ( callee_ty) = callee_ty else {
1449+ return ;
1450+ } ;
1451+ let ty:: Adt ( callee_adt, _) = callee_ty. peel_refs ( ) . kind ( ) else {
1452+ return ;
1453+ } ;
1454+ if !self . tcx . is_diagnostic_item ( sym:: Option , callee_adt. did ( ) ) {
1455+ return ;
1456+ }
1457+
1458+ if call_ident. map_or ( true , |ident| ident. name != sym:: unwrap_or) {
1459+ return ;
1460+ }
1461+
1462+ let ty:: Ref ( _, peeled, _mutability) = provided_ty. kind ( ) else {
1463+ return ;
1464+ } ;
1465+
1466+ // NOTE: Can we reuse `suggest_deref_or_ref`?
1467+
1468+ // Create an dummy type `&[_]` so that both &[] and `&Vec<T>` can coerce to it.
1469+ let dummy_ty = if let ty:: Array ( elem_ty, size) = peeled. kind ( )
1470+ && let ty:: Infer ( _) = elem_ty. kind ( )
1471+ && size. try_eval_target_usize ( self . tcx , self . param_env ) == Some ( 0 )
1472+ {
1473+ let slice = Ty :: new_slice ( self . tcx , * elem_ty) ;
1474+ Ty :: new_imm_ref ( self . tcx , self . tcx . lifetimes . re_static , slice)
1475+ } else {
1476+ provided_ty
1477+ } ;
1478+
1479+ if !self . can_coerce ( expected_ty, dummy_ty) {
1480+ return ;
1481+ }
1482+ let ( provided_snip, applicability) =
1483+ match self . tcx . sess . source_map ( ) . span_to_snippet ( provided_expr. span ) {
1484+ Ok ( snip) => ( snip, Applicability :: MachineApplicable ) ,
1485+ Err ( _) => ( "/* _ */" . to_owned ( ) , Applicability :: MaybeIncorrect ) ,
1486+ } ;
1487+ let sugg = & format ! ( "map_or({provided_snip}, |v| v)" ) ;
1488+ err. span_suggestion_verbose (
1489+ error_span,
1490+ "use `Option::map_or` to deref inner value of `Option`" ,
1491+ sugg,
1492+ applicability,
1493+ ) ;
1494+ return ;
1495+ }
1496+
14321497 /// Suggest wrapping the block in square brackets instead of curly braces
14331498 /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
14341499 pub ( crate ) fn suggest_block_to_brackets (
0 commit comments