@@ -8,7 +8,7 @@ use crate::method::probe;
8
8
use crate :: method:: probe:: { IsSuggestion , Mode , ProbeScope } ;
9
9
use core:: cmp:: min;
10
10
use core:: iter;
11
- use hir:: def_id:: { LocalDefId } ;
11
+ use hir:: def_id:: LocalDefId ;
12
12
use rustc_ast:: util:: parser:: { ExprPrecedence , PREC_UNAMBIGUOUS } ;
13
13
use rustc_data_structures:: packed:: Pu128 ;
14
14
use rustc_errors:: { Applicability , Diag , MultiSpan } ;
@@ -1429,6 +1429,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1429
1429
true
1430
1430
}
1431
1431
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
+
1432
1497
/// Suggest wrapping the block in square brackets instead of curly braces
1433
1498
/// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
1434
1499
pub ( crate ) fn suggest_block_to_brackets (
0 commit comments