@@ -11,21 +11,20 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
11
11
use rustc_middle:: ty:: { self as ty, IsSuggestable , Ty , TypeVisitable } ;
12
12
use rustc_span:: { sym, BytePos , Span } ;
13
13
14
- use crate :: errors:: SuggAddLetForLetChains ;
14
+ use crate :: errors:: { SuggAddLetForLetChains , SuggestRemoveSemiOrReturnBinding } ;
15
15
16
16
use super :: TypeErrCtxt ;
17
17
18
18
impl < ' tcx > TypeErrCtxt < ' _ , ' tcx > {
19
19
pub ( super ) fn suggest_remove_semi_or_return_binding (
20
20
& self ,
21
- err : & mut Diagnostic ,
22
21
first_id : Option < hir:: HirId > ,
23
22
first_ty : Ty < ' tcx > ,
24
23
first_span : Span ,
25
24
second_id : Option < hir:: HirId > ,
26
25
second_ty : Ty < ' tcx > ,
27
26
second_span : Span ,
28
- ) {
27
+ ) -> Option < SuggestRemoveSemiOrReturnBinding > {
29
28
let remove_semicolon = [
30
29
( first_id, self . resolve_vars_if_possible ( second_ty) ) ,
31
30
( second_id, self . resolve_vars_if_possible ( first_ty) ) ,
@@ -37,35 +36,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
37
36
} ) ;
38
37
match remove_semicolon {
39
38
Some ( ( sp, StatementAsExpression :: NeedsBoxing ) ) => {
40
- err. multipart_suggestion (
41
- "consider removing this semicolon and boxing the expressions" ,
42
- vec ! [
43
- ( first_span. shrink_to_lo( ) , "Box::new(" . to_string( ) ) ,
44
- ( first_span. shrink_to_hi( ) , ")" . to_string( ) ) ,
45
- ( second_span. shrink_to_lo( ) , "Box::new(" . to_string( ) ) ,
46
- ( second_span. shrink_to_hi( ) , ")" . to_string( ) ) ,
47
- ( sp, String :: new( ) ) ,
48
- ] ,
49
- Applicability :: MachineApplicable ,
50
- ) ;
39
+ Some ( SuggestRemoveSemiOrReturnBinding :: RemoveAndBox {
40
+ first_lo : first_span. shrink_to_lo ( ) ,
41
+ first_hi : first_span. shrink_to_hi ( ) ,
42
+ second_lo : second_span. shrink_to_lo ( ) ,
43
+ second_hi : second_span. shrink_to_hi ( ) ,
44
+ sp,
45
+ } )
51
46
}
52
47
Some ( ( sp, StatementAsExpression :: CorrectType ) ) => {
53
- err. span_suggestion_short (
54
- sp,
55
- "consider removing this semicolon" ,
56
- "" ,
57
- Applicability :: MachineApplicable ,
58
- ) ;
48
+ Some ( SuggestRemoveSemiOrReturnBinding :: Remove { sp } )
59
49
}
60
50
None => {
51
+ let mut ret = None ;
61
52
for ( id, ty) in [ ( first_id, second_ty) , ( second_id, first_ty) ] {
62
53
if let Some ( id) = id
63
54
&& let hir:: Node :: Block ( blk) = self . tcx . hir ( ) . get ( id)
64
- && self . consider_returning_binding ( blk, ty, err )
55
+ && let Some ( diag ) = self . consider_returning_binding_diag ( blk, ty)
65
56
{
57
+ ret = Some ( diag) ;
66
58
break ;
67
59
}
68
60
}
61
+ ret
69
62
}
70
63
}
71
64
}
@@ -655,16 +648,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
655
648
656
649
/// Suggest returning a local binding with a compatible type if the block
657
650
/// has no return expression.
658
- pub fn consider_returning_binding (
651
+ pub fn consider_returning_binding_diag (
659
652
& self ,
660
653
blk : & ' tcx hir:: Block < ' tcx > ,
661
654
expected_ty : Ty < ' tcx > ,
662
- err : & mut Diagnostic ,
663
- ) -> bool {
655
+ ) -> Option < SuggestRemoveSemiOrReturnBinding > {
664
656
let blk = blk. innermost_block ( ) ;
665
657
// Do not suggest if we have a tail expr.
666
658
if blk. expr . is_some ( ) {
667
- return false ;
659
+ return None ;
668
660
}
669
661
let mut shadowed = FxIndexSet :: default ( ) ;
670
662
let mut candidate_idents = vec ! [ ] ;
@@ -733,7 +725,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
733
725
match & candidate_idents[ ..] {
734
726
[ ( ident, _ty) ] => {
735
727
let sm = self . tcx . sess . source_map ( ) ;
736
- if let Some ( stmt) = blk. stmts . last ( ) {
728
+ let ( span , sugg ) = if let Some ( stmt) = blk. stmts . last ( ) {
737
729
let stmt_span = sm. stmt_span ( stmt. span , blk. span ) ;
738
730
let sugg = if sm. is_multiline ( blk. span )
739
731
&& let Some ( spacing) = sm. indentation_before ( stmt_span)
@@ -742,12 +734,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
742
734
} else {
743
735
format ! ( " {ident}" )
744
736
} ;
745
- err. span_suggestion_verbose (
746
- stmt_span. shrink_to_hi ( ) ,
747
- format ! ( "consider returning the local binding `{ident}`" ) ,
748
- sugg,
749
- Applicability :: MaybeIncorrect ,
750
- ) ;
737
+ ( stmt_span. shrink_to_hi ( ) , sugg)
751
738
} else {
752
739
let sugg = if sm. is_multiline ( blk. span )
753
740
&& let Some ( spacing) = sm. indentation_before ( blk. span . shrink_to_lo ( ) )
@@ -757,21 +744,34 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
757
744
format ! ( " {ident} " )
758
745
} ;
759
746
let left_span = sm. span_through_char ( blk. span , '{' ) . shrink_to_hi ( ) ;
760
- err . span_suggestion_verbose (
747
+ (
761
748
sm. span_extend_while ( left_span, |c| c. is_whitespace ( ) ) . unwrap_or ( left_span) ,
762
- format ! ( "consider returning the local binding `{ident}`" ) ,
763
749
sugg,
764
- Applicability :: MaybeIncorrect ,
765
- ) ;
766
- }
767
- true
750
+ )
751
+ } ;
752
+ Some ( SuggestRemoveSemiOrReturnBinding :: Add { sp : span, code : sugg, ident : * ident } )
768
753
}
769
754
values if ( 1 ..3 ) . contains ( & values. len ( ) ) => {
770
755
let spans = values. iter ( ) . map ( |( ident, _) | ident. span ) . collect :: < Vec < _ > > ( ) ;
771
- err. span_note ( spans, "consider returning one of these bindings" ) ;
756
+ Some ( SuggestRemoveSemiOrReturnBinding :: AddOne { spans : spans. into ( ) } )
757
+ }
758
+ _ => None ,
759
+ }
760
+ }
761
+
762
+ pub fn consider_returning_binding (
763
+ & self ,
764
+ blk : & ' tcx hir:: Block < ' tcx > ,
765
+ expected_ty : Ty < ' tcx > ,
766
+ err : & mut Diagnostic ,
767
+ ) -> bool {
768
+ let diag = self . consider_returning_binding_diag ( blk, expected_ty) ;
769
+ match diag {
770
+ Some ( diag) => {
771
+ err. subdiagnostic ( diag) ;
772
772
true
773
773
}
774
- _ => false ,
774
+ None => false ,
775
775
}
776
776
}
777
777
}
0 commit comments