@@ -63,10 +63,11 @@ use rustc_hir::{self as hir};
6363use  rustc_macros:: extension; 
6464use  rustc_middle:: bug; 
6565use  rustc_middle:: dep_graph:: DepContext ; 
66+ use  rustc_middle:: traits:: PatternOriginExpr ; 
6667use  rustc_middle:: ty:: error:: { ExpectedFound ,  TypeError ,  TypeErrorToStringExt } ; 
6768use  rustc_middle:: ty:: print:: { PrintError ,  PrintTraitRefExt  as  _,  with_forced_trimmed_paths} ; 
6869use  rustc_middle:: ty:: { 
69-     self ,  List ,  Region ,  Ty ,  TyCtxt ,  TypeFoldable ,  TypeSuperVisitable ,  TypeVisitable , 
70+     self ,  List ,  ParamEnv ,   Region ,  Ty ,  TyCtxt ,  TypeFoldable ,  TypeSuperVisitable ,  TypeVisitable , 
7071    TypeVisitableExt , 
7172} ; 
7273use  rustc_span:: def_id:: LOCAL_CRATE ; 
@@ -77,7 +78,7 @@ use crate::error_reporting::TypeErrCtxt;
7778use  crate :: errors:: { ObligationCauseFailureCode ,  TypeErrorAdditionalDiags } ; 
7879use  crate :: infer; 
7980use  crate :: infer:: relate:: { self ,  RelateResult ,  TypeRelation } ; 
80- use  crate :: infer:: { InferCtxt ,  TypeTrace ,  ValuePairs } ; 
81+ use  crate :: infer:: { InferCtxt ,  InferCtxtExt   as  _ ,   TypeTrace ,  ValuePairs } ; 
8182use  crate :: solve:: deeply_normalize_for_diagnostics; 
8283use  crate :: traits:: { 
8384    IfExpressionCause ,  MatchExpressionArmCause ,  ObligationCause ,  ObligationCauseCode , 
@@ -433,38 +434,71 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
433434        cause :  & ObligationCause < ' tcx > , 
434435        exp_found :  Option < ty:: error:: ExpectedFound < Ty < ' tcx > > > , 
435436        terr :  TypeError < ' tcx > , 
437+         param_env :  Option < ParamEnv < ' tcx > > , 
436438    )  { 
437439        match  * cause. code ( )  { 
438-             ObligationCauseCode :: Pattern  {  origin_expr :  true ,  span :  Some ( span) ,  root_ty }  => { 
439-                 let  ty = self . resolve_vars_if_possible ( root_ty) ; 
440-                 if  !matches ! ( ty. kind( ) ,  ty:: Infer ( ty:: InferTy :: TyVar ( _)  | ty:: InferTy :: FreshTy ( _) ) ) 
441-                 { 
440+             ObligationCauseCode :: Pattern  { 
441+                 origin_expr :  Some ( origin_expr) , 
442+                 span :  Some ( span) , 
443+                 root_ty, 
444+             }  => { 
445+                 let  expected_ty = self . resolve_vars_if_possible ( root_ty) ; 
446+                 if  !matches ! ( 
447+                     expected_ty. kind( ) , 
448+                     ty:: Infer ( ty:: InferTy :: TyVar ( _)  | ty:: InferTy :: FreshTy ( _) ) 
449+                 )  { 
442450                    // don't show type `_` 
443451                    if  span. desugaring_kind ( )  == Some ( DesugaringKind :: ForLoop ) 
444-                         && let  ty:: Adt ( def,  args)  = ty . kind ( ) 
452+                         && let  ty:: Adt ( def,  args)  = expected_ty . kind ( ) 
445453                        && Some ( def. did ( ) )  == self . tcx . get_diagnostic_item ( sym:: Option ) 
446454                    { 
447455                        err. span_label ( 
448456                            span, 
449457                            format ! ( "this is an iterator with items of type `{}`" ,  args. type_at( 0 ) ) , 
450458                        ) ; 
451459                    }  else  { 
452-                         err. span_label ( span,  format ! ( "this expression has type `{ty }`" ) ) ; 
460+                         err. span_label ( span,  format ! ( "this expression has type `{expected_ty }`" ) ) ; 
453461                    } 
454462                } 
455463                if  let  Some ( ty:: error:: ExpectedFound  {  found,  .. } )  = exp_found
456-                     && ty . boxed_ty ( )  ==  Some ( found ) 
457-                     &&  let   Ok ( snippet )  =  self . tcx . sess . source_map ( ) . span_to_snippet ( span ) 
464+                     && let   Ok ( mut  peeled_snippet )  =
465+                          self . tcx . sess . source_map ( ) . span_to_snippet ( origin_expr . peeled_span ) 
458466                { 
459-                     err. span_suggestion ( 
460-                         span, 
461-                         "consider dereferencing the boxed value" , 
462-                         format ! ( "*{snippet}" ) , 
463-                         Applicability :: MachineApplicable , 
464-                     ) ; 
467+                     // Parentheses are needed for cases like as casts. 
468+                     // We use the peeled_span for deref suggestions. 
469+                     // It's also safe to use for box, since box only triggers if there 
470+                     // wasn't a reference to begin with. 
471+                     if  origin_expr. peeled_prefix_suggestion_parentheses  { 
472+                         peeled_snippet = format ! ( "({peeled_snippet})" ) ; 
473+                     } 
474+ 
475+                     // Try giving a box suggestion first, as it is a special case of the 
476+                     // deref suggestion. 
477+                     if  expected_ty. boxed_ty ( )  == Some ( found)  { 
478+                         err. span_suggestion_verbose ( 
479+                             span, 
480+                             "consider dereferencing the boxed value" , 
481+                             format ! ( "*{peeled_snippet}" ) , 
482+                             Applicability :: MachineApplicable , 
483+                         ) ; 
484+                     }  else  if  let  Some ( param_env)  = param_env
485+                         && let  Some ( prefix)  = self . should_deref_suggestion_on_mismatch ( 
486+                             param_env, 
487+                             found, 
488+                             expected_ty, 
489+                             origin_expr, 
490+                         ) 
491+                     { 
492+                         err. span_suggestion_verbose ( 
493+                             span, 
494+                             "consider dereferencing to access the inner value using the Deref trait" , 
495+                             format ! ( "{prefix}{peeled_snippet}" ) , 
496+                             Applicability :: MaybeIncorrect , 
497+                         ) ; 
498+                     } 
465499                } 
466500            } 
467-             ObligationCauseCode :: Pattern  {  origin_expr :  false ,  span :  Some ( span) ,  .. }  => { 
501+             ObligationCauseCode :: Pattern  {  origin_expr :  None ,  span :  Some ( span) ,  .. }  => { 
468502                err. span_label ( span,  "expected due to this" ) ; 
469503            } 
470504            ObligationCauseCode :: BlockTailExpression ( 
@@ -618,6 +652,45 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
618652        } 
619653    } 
620654
655+     /// Determines whether deref_to == <deref_from as Deref>::Target, and if so, 
656+ /// returns a prefix that should be added to deref_from as a suggestion. 
657+ fn  should_deref_suggestion_on_mismatch ( 
658+         & self , 
659+         param_env :  ParamEnv < ' tcx > , 
660+         deref_to :  Ty < ' tcx > , 
661+         deref_from :  Ty < ' tcx > , 
662+         origin_expr :  PatternOriginExpr , 
663+     )  -> Option < String >  { 
664+         // origin_expr contains stripped away versions of our expression. 
665+         // We'll want to use that to avoid suggesting things like *&x. 
666+         // However, the type that we have access to hasn't been stripped away, 
667+         // so we need to ignore the first n dereferences, where n is the number 
668+         // that's been stripped away in origin_expr. 
669+ 
670+         // Find a way to autoderef from deref_from to deref_to. 
671+         let  Some ( ( num_derefs,  ( after_deref_ty,  _) ) )  = ( self . autoderef_steps ) ( deref_from) 
672+             . into_iter ( ) 
673+             . enumerate ( ) 
674+             . find ( |( _,  ( ty,  _) ) | self . infcx . can_eq ( param_env,  * ty,  deref_to) ) 
675+         else  { 
676+             return  None ; 
677+         } ; 
678+ 
679+         if  num_derefs <= origin_expr. peeled_count  { 
680+             return  None ; 
681+         } 
682+ 
683+         let  deref_part = "*" . repeat ( num_derefs - origin_expr. peeled_count ) ; 
684+ 
685+         // If the user used a reference in the original expression, they probably 
686+         // want the suggestion to still give a reference. 
687+         if  deref_from. is_ref ( )  && !after_deref_ty. is_ref ( )  { 
688+             Some ( format ! ( "&{deref_part}" ) ) 
689+         }  else  { 
690+             Some ( deref_part) 
691+         } 
692+     } 
693+ 
621694    /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` 
622695/// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and 
623696/// populate `other_value` with `other_ty`. 
@@ -1406,8 +1479,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
14061479            Variable ( ty:: error:: ExpectedFound < Ty < ' a > > ) , 
14071480            Fixed ( & ' static  str ) , 
14081481        } 
1409-         let  ( expected_found,  exp_found,  is_simple_error,  values)  = match  values { 
1410-             None  => ( None ,  Mismatch :: Fixed ( "type" ) ,  false ,  None ) , 
1482+         let  ( expected_found,  exp_found,  is_simple_error,  values,  param_env )  = match  values { 
1483+             None  => ( None ,  Mismatch :: Fixed ( "type" ) ,  false ,  None ,   None ) , 
14111484            Some ( ty:: ParamEnvAnd  {  param_env,  value :  values } )  => { 
14121485                let  mut  values = self . resolve_vars_if_possible ( values) ; 
14131486                if  self . next_trait_solver ( )  { 
@@ -1459,7 +1532,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
14591532                    diag. downgrade_to_delayed_bug ( ) ; 
14601533                    return ; 
14611534                } ; 
1462-                 ( Some ( vals) ,  exp_found,  is_simple_error,  Some ( values) ) 
1535+                 ( Some ( vals) ,  exp_found,  is_simple_error,  Some ( values) ,   Some ( param_env ) ) 
14631536            } 
14641537        } ; 
14651538
@@ -1791,7 +1864,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
17911864
17921865        // It reads better to have the error origin as the final 
17931866        // thing. 
1794-         self . note_error_origin ( diag,  cause,  exp_found,  terr) ; 
1867+         self . note_error_origin ( diag,  cause,  exp_found,  terr,  param_env ) ; 
17951868
17961869        debug ! ( ?diag) ; 
17971870    } 
0 commit comments