@@ -11,21 +11,20 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
1111use rustc_middle:: ty:: { self as ty, IsSuggestable , Ty , TypeVisitable } ;
1212use rustc_span:: { sym, BytePos , Span } ;
1313
14- use crate :: errors:: SuggAddLetForLetChains ;
14+ use crate :: errors:: { SuggAddLetForLetChains , SuggestRemoveSemiOrReturnBinding } ;
1515
1616use super :: TypeErrCtxt ;
1717
1818impl < ' tcx > TypeErrCtxt < ' _ , ' tcx > {
1919 pub ( super ) fn suggest_remove_semi_or_return_binding (
2020 & self ,
21- err : & mut Diagnostic ,
2221 first_id : Option < hir:: HirId > ,
2322 first_ty : Ty < ' tcx > ,
2423 first_span : Span ,
2524 second_id : Option < hir:: HirId > ,
2625 second_ty : Ty < ' tcx > ,
2726 second_span : Span ,
28- ) {
27+ ) -> Option < SuggestRemoveSemiOrReturnBinding > {
2928 let remove_semicolon = [
3029 ( first_id, self . resolve_vars_if_possible ( second_ty) ) ,
3130 ( second_id, self . resolve_vars_if_possible ( first_ty) ) ,
@@ -37,35 +36,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
3736 } ) ;
3837 match remove_semicolon {
3938 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+ } )
5146 }
5247 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 } )
5949 }
6050 None => {
51+ let mut ret = None ;
6152 for ( id, ty) in [ ( first_id, second_ty) , ( second_id, first_ty) ] {
6253 if let Some ( id) = id
6354 && 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)
6556 {
57+ ret = Some ( diag) ;
6658 break ;
6759 }
6860 }
61+ ret
6962 }
7063 }
7164 }
@@ -655,16 +648,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
655648
656649 /// Suggest returning a local binding with a compatible type if the block
657650 /// has no return expression.
658- pub fn consider_returning_binding (
651+ pub fn consider_returning_binding_diag (
659652 & self ,
660653 blk : & ' tcx hir:: Block < ' tcx > ,
661654 expected_ty : Ty < ' tcx > ,
662- err : & mut Diagnostic ,
663- ) -> bool {
655+ ) -> Option < SuggestRemoveSemiOrReturnBinding > {
664656 let blk = blk. innermost_block ( ) ;
665657 // Do not suggest if we have a tail expr.
666658 if blk. expr . is_some ( ) {
667- return false ;
659+ return None ;
668660 }
669661 let mut shadowed = FxIndexSet :: default ( ) ;
670662 let mut candidate_idents = vec ! [ ] ;
@@ -733,7 +725,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
733725 match & candidate_idents[ ..] {
734726 [ ( ident, _ty) ] => {
735727 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 ( ) {
737729 let stmt_span = sm. stmt_span ( stmt. span , blk. span ) ;
738730 let sugg = if sm. is_multiline ( blk. span )
739731 && let Some ( spacing) = sm. indentation_before ( stmt_span)
@@ -742,12 +734,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
742734 } else {
743735 format ! ( " {ident}" )
744736 } ;
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)
751738 } else {
752739 let sugg = if sm. is_multiline ( blk. span )
753740 && let Some ( spacing) = sm. indentation_before ( blk. span . shrink_to_lo ( ) )
@@ -757,21 +744,34 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
757744 format ! ( " {ident} " )
758745 } ;
759746 let left_span = sm. span_through_char ( blk. span , '{' ) . shrink_to_hi ( ) ;
760- err . span_suggestion_verbose (
747+ (
761748 sm. span_extend_while ( left_span, |c| c. is_whitespace ( ) ) . unwrap_or ( left_span) ,
762- format ! ( "consider returning the local binding `{ident}`" ) ,
763749 sugg,
764- Applicability :: MaybeIncorrect ,
765- ) ;
766- }
767- true
750+ )
751+ } ;
752+ Some ( SuggestRemoveSemiOrReturnBinding :: Add { sp : span, code : sugg, ident : * ident } )
768753 }
769754 values if ( 1 ..3 ) . contains ( & values. len ( ) ) => {
770755 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) ;
772772 true
773773 }
774- _ => false ,
774+ None => false ,
775775 }
776776 }
777777}
0 commit comments