@@ -3,7 +3,7 @@ use crate::astconv::AstConv;
33use crate :: errors:: { AddReturnTypeSuggestion , ExpectedReturnTypeLabel } ;
44
55use hir:: def_id:: DefId ;
6- use rustc_ast:: util:: parser:: ExprPrecedence ;
6+ use rustc_ast:: util:: parser:: { ExprPrecedence , PREC_POSTFIX } ;
77use rustc_errors:: { Applicability , Diagnostic , MultiSpan } ;
88use rustc_hir as hir;
99use rustc_hir:: def:: { CtorOf , DefKind } ;
@@ -327,7 +327,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
327327 expected : Ty < ' tcx > ,
328328 found : Ty < ' tcx > ,
329329 expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
330- ) {
330+ ) -> bool {
331331 let expr = expr. peel_blocks ( ) ;
332332 if let Some ( ( sp, msg, suggestion, applicability, verbose) ) =
333333 self . check_ref ( expr, found, expected)
@@ -337,14 +337,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
337337 } else {
338338 err. span_suggestion ( sp, & msg, suggestion, applicability) ;
339339 }
340+ return true ;
340341 } else if self . suggest_else_fn_with_closure ( err, expr, found, expected)
341342 {
343+ return true ;
342344 } else if self . suggest_fn_call ( err, expr, found, |output| self . can_coerce ( output, expected) )
343345 && let ty:: FnDef ( def_id, ..) = & found. kind ( )
344346 && let Some ( sp) = self . tcx . hir ( ) . span_if_local ( * def_id)
345347 {
346348 err. span_label ( sp, format ! ( "{found} defined here" ) ) ;
347- } else if !self . check_for_cast ( err, expr, found, expected, expected_ty_expr) {
349+ return true ;
350+ } else if self . check_for_cast ( err, expr, found, expected, expected_ty_expr) {
351+ return true ;
352+ } else {
348353 let methods = self . get_conversion_methods ( expr. span , expected, found, expr. hir_id ) ;
349354 if !methods. is_empty ( ) {
350355 let mut suggestions = methods. iter ( )
@@ -395,6 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
395400 suggestions,
396401 Applicability :: MaybeIncorrect ,
397402 ) ;
403+ return true ;
398404 }
399405 } else if let ty:: Adt ( found_adt, found_substs) = found. kind ( )
400406 && self . tcx . is_diagnostic_item ( sym:: Option , found_adt. did ( ) )
@@ -419,9 +425,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
419425 format ! ( ".map(|x| &*{}x)" , "*" . repeat( ref_cnt) ) ,
420426 Applicability :: MaybeIncorrect ,
421427 ) ;
428+ return true ;
422429 }
423430 }
424431 }
432+
433+ false
425434 }
426435
427436 /// When encountering the expected boxed value allocated in the stack, suggest allocating it
@@ -432,13 +441,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
432441 expr : & hir:: Expr < ' _ > ,
433442 expected : Ty < ' tcx > ,
434443 found : Ty < ' tcx > ,
435- ) {
444+ ) -> bool {
436445 if self . tcx . hir ( ) . is_inside_const_context ( expr. hir_id ) {
437446 // Do not suggest `Box::new` in const context.
438- return ;
447+ return false ;
439448 }
440449 if !expected. is_box ( ) || found. is_box ( ) {
441- return ;
450+ return false ;
442451 }
443452 let boxed_found = self . tcx . mk_box ( found) ;
444453 if self . can_coerce ( boxed_found, expected) {
@@ -456,6 +465,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
456465 https://doc.rust-lang.org/rust-by-example/std/box.html, and \
457466 https://doc.rust-lang.org/std/boxed/index.html",
458467 ) ;
468+ true
469+ } else {
470+ false
459471 }
460472 }
461473
@@ -466,7 +478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
466478 err : & mut Diagnostic ,
467479 expected : Ty < ' tcx > ,
468480 found : Ty < ' tcx > ,
469- ) {
481+ ) -> bool {
470482 if let ( ty:: FnPtr ( _) , ty:: Closure ( def_id, _) ) = ( expected. kind ( ) , found. kind ( ) ) {
471483 if let Some ( upvars) = self . tcx . upvars_mentioned ( * def_id) {
472484 // Report upto four upvars being captured to reduce the amount error messages
@@ -490,8 +502,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
490502 multi_span,
491503 "closures can only be coerced to `fn` types if they do not capture any variables"
492504 ) ;
505+ return true ;
493506 }
494507 }
508+ false
495509 }
496510
497511 /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
@@ -893,11 +907,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
893907 & self ,
894908 err : & mut Diagnostic ,
895909 expr : & hir:: Expr < ' _ > ,
896- ) {
910+ ) -> bool {
897911 let sp = self . tcx . sess . source_map ( ) . start_point ( expr. span ) ;
898912 if let Some ( sp) = self . tcx . sess . parse_sess . ambiguous_block_expr_parse . borrow ( ) . get ( & sp) {
899913 // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
900914 err. subdiagnostic ( ExprParenthesesNeeded :: surrounding ( * sp) ) ;
915+ true
916+ } else {
917+ false
901918 }
902919 }
903920
@@ -910,7 +927,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
910927 mut expr : & hir:: Expr < ' _ > ,
911928 mut expr_ty : Ty < ' tcx > ,
912929 mut expected_ty : Ty < ' tcx > ,
913- ) {
930+ ) -> bool {
914931 loop {
915932 match ( & expr. kind , expr_ty. kind ( ) , expected_ty. kind ( ) ) {
916933 (
@@ -924,9 +941,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
924941 }
925942 ( hir:: ExprKind :: Block ( blk, _) , _, _) => {
926943 self . suggest_block_to_brackets ( diag, * blk, expr_ty, expected_ty) ;
927- break ;
944+ break true ;
928945 }
929- _ => break ,
946+ _ => break false ,
930947 }
931948 }
932949 }
@@ -937,11 +954,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
937954 expr : & hir:: Expr < ' _ > ,
938955 expr_ty : Ty < ' tcx > ,
939956 expected_ty : Ty < ' tcx > ,
940- ) {
941- let ty:: Adt ( adt_def, substs) = expr_ty. kind ( ) else { return ; } ;
942- let ty:: Adt ( expected_adt_def, expected_substs) = expected_ty. kind ( ) else { return ; } ;
957+ ) -> bool {
958+ let ty:: Adt ( adt_def, substs) = expr_ty. kind ( ) else { return false ; } ;
959+ let ty:: Adt ( expected_adt_def, expected_substs) = expected_ty. kind ( ) else { return false ; } ;
943960 if adt_def != expected_adt_def {
944- return ;
961+ return false ;
945962 }
946963
947964 let mut suggest_copied_or_cloned = || {
@@ -960,6 +977,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
960977 ".copied()" ,
961978 Applicability :: MachineApplicable ,
962979 ) ;
980+ return true ;
963981 } else if let Some ( clone_did) = self . tcx . lang_items ( ) . clone_trait ( )
964982 && rustc_trait_selection:: traits:: type_known_to_meet_bound_modulo_regions (
965983 self ,
@@ -977,21 +995,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
977995 ".cloned()" ,
978996 Applicability :: MachineApplicable ,
979997 ) ;
998+ return true ;
980999 }
9811000 }
1001+ false
9821002 } ;
9831003
9841004 if let Some ( result_did) = self . tcx . get_diagnostic_item ( sym:: Result )
9851005 && adt_def. did ( ) == result_did
9861006 // Check that the error types are equal
9871007 && self . can_eq ( self . param_env , substs. type_at ( 1 ) , expected_substs. type_at ( 1 ) ) . is_ok ( )
9881008 {
989- suggest_copied_or_cloned ( ) ;
1009+ return suggest_copied_or_cloned ( ) ;
9901010 } else if let Some ( option_did) = self . tcx . get_diagnostic_item ( sym:: Option )
9911011 && adt_def. did ( ) == option_did
9921012 {
993- suggest_copied_or_cloned ( ) ;
1013+ return suggest_copied_or_cloned ( ) ;
1014+ }
1015+
1016+ false
1017+ }
1018+
1019+ pub ( crate ) fn suggest_into (
1020+ & self ,
1021+ diag : & mut Diagnostic ,
1022+ expr : & hir:: Expr < ' _ > ,
1023+ expr_ty : Ty < ' tcx > ,
1024+ expected_ty : Ty < ' tcx > ,
1025+ ) -> bool {
1026+ let expr = expr. peel_blocks ( ) ;
1027+
1028+ // We have better suggestions for scalar interconversions...
1029+ if expr_ty. is_scalar ( ) && expected_ty. is_scalar ( ) {
1030+ return false ;
9941031 }
1032+
1033+ // Don't suggest turning a block into another type (e.g. `{}.into()`)
1034+ if matches ! ( expr. kind, hir:: ExprKind :: Block ( ..) ) {
1035+ return false ;
1036+ }
1037+
1038+ // We'll later suggest `.as_ref` when noting the type error,
1039+ // so skip if we will suggest that instead.
1040+ if self . should_suggest_as_ref ( expected_ty, expr_ty) . is_some ( ) {
1041+ return false ;
1042+ }
1043+
1044+ if let Some ( into_def_id) = self . tcx . get_diagnostic_item ( sym:: Into )
1045+ && self . predicate_must_hold_modulo_regions ( & traits:: Obligation :: new (
1046+ self . misc ( expr. span ) ,
1047+ self . param_env ,
1048+ ty:: Binder :: dummy ( ty:: TraitRef {
1049+ def_id : into_def_id,
1050+ substs : self . tcx . mk_substs_trait ( expr_ty, & [ expected_ty. into ( ) ] ) ,
1051+ } )
1052+ . to_poly_trait_predicate ( )
1053+ . to_predicate ( self . tcx ) ,
1054+ ) )
1055+ {
1056+ let sugg = if expr. precedence ( ) . order ( ) >= PREC_POSTFIX {
1057+ vec ! [ ( expr. span. shrink_to_hi( ) , ".into()" . to_owned( ) ) ]
1058+ } else {
1059+ vec ! [ ( expr. span. shrink_to_lo( ) , "(" . to_owned( ) ) , ( expr. span. shrink_to_hi( ) , ").into()" . to_owned( ) ) ]
1060+ } ;
1061+ diag. multipart_suggestion (
1062+ format ! ( "call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`" ) ,
1063+ sugg,
1064+ Applicability :: MaybeIncorrect
1065+ ) ;
1066+ return true ;
1067+ }
1068+
1069+ false
9951070 }
9961071
9971072 /// Suggest wrapping the block in square brackets instead of curly braces
0 commit comments