1+ use crate :: check:: coercion:: Coerce ;
12use crate :: check:: FnCtxt ;
23use rustc_infer:: infer:: InferOk ;
34use rustc_trait_selection:: infer:: InferCtxtExt as _;
@@ -8,8 +9,9 @@ use rustc_ast::util::parser::PREC_POSTFIX;
89use rustc_errors:: { Applicability , DiagnosticBuilder } ;
910use rustc_hir as hir;
1011use rustc_hir:: { is_range_literal, Node } ;
12+ use rustc_middle:: traits:: ObligationCauseCode ;
1113use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
12- use rustc_middle:: ty:: { self , AssocItem , Ty } ;
14+ use rustc_middle:: ty:: { self , AssocItem , Ty , TypeAndMut } ;
1315use rustc_span:: symbol:: sym;
1416use rustc_span:: Span ;
1517
@@ -25,7 +27,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2527 ) {
2628 self . annotate_expected_due_to_let_ty ( err, expr) ;
2729 self . suggest_compatible_variants ( err, expr, expected, expr_ty) ;
28- self . suggest_ref_or_into ( err, expr, expected, expr_ty) ;
30+ self . suggest_deref_ref_or_into ( err, expr, expected, expr_ty) ;
2931 if self . suggest_calling_boxed_future_when_appropriate ( err, expr, expected, expr_ty) {
3032 return ;
3133 }
@@ -539,6 +541,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
539541 return Some ( ( sp, "consider removing the borrow" , code) ) ;
540542 }
541543 }
544+ (
545+ _,
546+ & ty:: RawPtr ( TypeAndMut { ty : _, mutbl : hir:: Mutability :: Not } ) ,
547+ & ty:: Ref ( _, _, hir:: Mutability :: Not ) ,
548+ ) => {
549+ let cause = self . cause ( rustc_span:: DUMMY_SP , ObligationCauseCode :: ExprAssignable ) ;
550+ // We don't ever need two-phase here since we throw out the result of the coercion
551+ let coerce = Coerce :: new ( self , cause, AllowTwoPhase :: No ) ;
552+
553+ if let Some ( steps) =
554+ coerce. autoderef ( sp, checked_ty) . skip ( 1 ) . find_map ( |( referent_ty, steps) | {
555+ coerce
556+ . unify (
557+ coerce. tcx . mk_ptr ( ty:: TypeAndMut {
558+ mutbl : hir:: Mutability :: Not ,
559+ ty : referent_ty,
560+ } ) ,
561+ expected,
562+ )
563+ . ok ( )
564+ . map ( |_| steps)
565+ } )
566+ {
567+ // The pointer type implements `Copy` trait so the suggestion is always valid.
568+ if let Ok ( code) = sm. span_to_snippet ( sp) {
569+ if code. starts_with ( '&' ) {
570+ let derefs = "*" . repeat ( steps - 1 ) ;
571+ let message = "consider dereferencing the reference" ;
572+ let suggestion = format ! ( "&{}{}" , derefs, code[ 1 ..] . to_string( ) ) ;
573+ return Some ( ( sp, message, suggestion) ) ;
574+ }
575+ }
576+ }
577+ }
542578 _ if sp == expr. span && !is_macro => {
543579 // Check for `Deref` implementations by constructing a predicate to
544580 // prove: `<T as Deref>::Output == U`
0 commit comments