1
+ use crate :: check:: coercion:: Coerce ;
1
2
use crate :: check:: FnCtxt ;
2
3
use rustc_infer:: infer:: InferOk ;
3
4
use rustc_trait_selection:: infer:: InferCtxtExt as _;
@@ -8,8 +9,9 @@ use rustc_ast::util::parser::PREC_POSTFIX;
8
9
use rustc_errors:: { Applicability , DiagnosticBuilder } ;
9
10
use rustc_hir as hir;
10
11
use rustc_hir:: { is_range_literal, Node } ;
12
+ use rustc_middle:: traits:: ObligationCauseCode ;
11
13
use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
12
- use rustc_middle:: ty:: { self , AssocItem , Ty } ;
14
+ use rustc_middle:: ty:: { self , AssocItem , Ty , TypeAndMut } ;
13
15
use rustc_span:: symbol:: sym;
14
16
use rustc_span:: Span ;
15
17
@@ -25,7 +27,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25
27
) {
26
28
self . annotate_expected_due_to_let_ty ( err, expr) ;
27
29
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) ;
29
31
if self . suggest_calling_boxed_future_when_appropriate ( err, expr, expected, expr_ty) {
30
32
return ;
31
33
}
@@ -539,6 +541,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
539
541
return Some ( ( sp, "consider removing the borrow" , code) ) ;
540
542
}
541
543
}
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
+ }
542
578
_ if sp == expr. span && !is_macro => {
543
579
// Check for `Deref` implementations by constructing a predicate to
544
580
// prove: `<T as Deref>::Output == U`
0 commit comments