@@ -3,7 +3,7 @@ use crate::astconv::AstConv;
3
3
use crate :: errors:: { AddReturnTypeSuggestion , ExpectedReturnTypeLabel } ;
4
4
5
5
use hir:: def_id:: DefId ;
6
- use rustc_ast:: util:: parser:: ExprPrecedence ;
6
+ use rustc_ast:: util:: parser:: { ExprPrecedence , PREC_POSTFIX } ;
7
7
use rustc_errors:: { Applicability , Diagnostic , MultiSpan } ;
8
8
use rustc_hir as hir;
9
9
use rustc_hir:: def:: { CtorOf , DefKind } ;
@@ -327,7 +327,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
327
327
expected : Ty < ' tcx > ,
328
328
found : Ty < ' tcx > ,
329
329
expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
330
- ) {
330
+ ) -> bool {
331
331
let expr = expr. peel_blocks ( ) ;
332
332
if let Some ( ( sp, msg, suggestion, applicability, verbose) ) =
333
333
self . check_ref ( expr, found, expected)
@@ -337,14 +337,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
337
337
} else {
338
338
err. span_suggestion ( sp, & msg, suggestion, applicability) ;
339
339
}
340
+ return true ;
340
341
} else if self . suggest_else_fn_with_closure ( err, expr, found, expected)
341
342
{
343
+ return true ;
342
344
} else if self . suggest_fn_call ( err, expr, found, |output| self . can_coerce ( output, expected) )
343
345
&& let ty:: FnDef ( def_id, ..) = & found. kind ( )
344
346
&& let Some ( sp) = self . tcx . hir ( ) . span_if_local ( * def_id)
345
347
{
346
348
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 {
348
353
let methods = self . get_conversion_methods ( expr. span , expected, found, expr. hir_id ) ;
349
354
if !methods. is_empty ( ) {
350
355
let mut suggestions = methods. iter ( )
@@ -395,6 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
395
400
suggestions,
396
401
Applicability :: MaybeIncorrect ,
397
402
) ;
403
+ return true ;
398
404
}
399
405
} else if let ty:: Adt ( found_adt, found_substs) = found. kind ( )
400
406
&& self . tcx . is_diagnostic_item ( sym:: Option , found_adt. did ( ) )
@@ -419,9 +425,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
419
425
format ! ( ".map(|x| &*{}x)" , "*" . repeat( ref_cnt) ) ,
420
426
Applicability :: MaybeIncorrect ,
421
427
) ;
428
+ return true ;
422
429
}
423
430
}
424
431
}
432
+
433
+ false
425
434
}
426
435
427
436
/// When encountering the expected boxed value allocated in the stack, suggest allocating it
@@ -432,13 +441,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
432
441
expr : & hir:: Expr < ' _ > ,
433
442
expected : Ty < ' tcx > ,
434
443
found : Ty < ' tcx > ,
435
- ) {
444
+ ) -> bool {
436
445
if self . tcx . hir ( ) . is_inside_const_context ( expr. hir_id ) {
437
446
// Do not suggest `Box::new` in const context.
438
- return ;
447
+ return false ;
439
448
}
440
449
if !expected. is_box ( ) || found. is_box ( ) {
441
- return ;
450
+ return false ;
442
451
}
443
452
let boxed_found = self . tcx . mk_box ( found) ;
444
453
if self . can_coerce ( boxed_found, expected) {
@@ -456,6 +465,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
456
465
https://doc.rust-lang.org/rust-by-example/std/box.html, and \
457
466
https://doc.rust-lang.org/std/boxed/index.html",
458
467
) ;
468
+ true
469
+ } else {
470
+ false
459
471
}
460
472
}
461
473
@@ -466,7 +478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
466
478
err : & mut Diagnostic ,
467
479
expected : Ty < ' tcx > ,
468
480
found : Ty < ' tcx > ,
469
- ) {
481
+ ) -> bool {
470
482
if let ( ty:: FnPtr ( _) , ty:: Closure ( def_id, _) ) = ( expected. kind ( ) , found. kind ( ) ) {
471
483
if let Some ( upvars) = self . tcx . upvars_mentioned ( * def_id) {
472
484
// Report upto four upvars being captured to reduce the amount error messages
@@ -490,8 +502,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
490
502
multi_span,
491
503
"closures can only be coerced to `fn` types if they do not capture any variables"
492
504
) ;
505
+ return true ;
493
506
}
494
507
}
508
+ false
495
509
}
496
510
497
511
/// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
@@ -893,11 +907,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
893
907
& self ,
894
908
err : & mut Diagnostic ,
895
909
expr : & hir:: Expr < ' _ > ,
896
- ) {
910
+ ) -> bool {
897
911
let sp = self . tcx . sess . source_map ( ) . start_point ( expr. span ) ;
898
912
if let Some ( sp) = self . tcx . sess . parse_sess . ambiguous_block_expr_parse . borrow ( ) . get ( & sp) {
899
913
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
900
914
err. subdiagnostic ( ExprParenthesesNeeded :: surrounding ( * sp) ) ;
915
+ true
916
+ } else {
917
+ false
901
918
}
902
919
}
903
920
@@ -910,7 +927,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
910
927
mut expr : & hir:: Expr < ' _ > ,
911
928
mut expr_ty : Ty < ' tcx > ,
912
929
mut expected_ty : Ty < ' tcx > ,
913
- ) {
930
+ ) -> bool {
914
931
loop {
915
932
match ( & expr. kind , expr_ty. kind ( ) , expected_ty. kind ( ) ) {
916
933
(
@@ -924,9 +941,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
924
941
}
925
942
( hir:: ExprKind :: Block ( blk, _) , _, _) => {
926
943
self . suggest_block_to_brackets ( diag, * blk, expr_ty, expected_ty) ;
927
- break ;
944
+ break true ;
928
945
}
929
- _ => break ,
946
+ _ => break false ,
930
947
}
931
948
}
932
949
}
@@ -937,11 +954,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
937
954
expr : & hir:: Expr < ' _ > ,
938
955
expr_ty : Ty < ' tcx > ,
939
956
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 ; } ;
943
960
if adt_def != expected_adt_def {
944
- return ;
961
+ return false ;
945
962
}
946
963
947
964
let mut suggest_copied_or_cloned = || {
@@ -960,6 +977,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
960
977
".copied()" ,
961
978
Applicability :: MachineApplicable ,
962
979
) ;
980
+ return true ;
963
981
} else if let Some ( clone_did) = self . tcx . lang_items ( ) . clone_trait ( )
964
982
&& rustc_trait_selection:: traits:: type_known_to_meet_bound_modulo_regions (
965
983
self ,
@@ -977,21 +995,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
977
995
".cloned()" ,
978
996
Applicability :: MachineApplicable ,
979
997
) ;
998
+ return true ;
980
999
}
981
1000
}
1001
+ false
982
1002
} ;
983
1003
984
1004
if let Some ( result_did) = self . tcx . get_diagnostic_item ( sym:: Result )
985
1005
&& adt_def. did ( ) == result_did
986
1006
// Check that the error types are equal
987
1007
&& self . can_eq ( self . param_env , substs. type_at ( 1 ) , expected_substs. type_at ( 1 ) ) . is_ok ( )
988
1008
{
989
- suggest_copied_or_cloned ( ) ;
1009
+ return suggest_copied_or_cloned ( ) ;
990
1010
} else if let Some ( option_did) = self . tcx . get_diagnostic_item ( sym:: Option )
991
1011
&& adt_def. did ( ) == option_did
992
1012
{
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 ;
994
1031
}
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
995
1070
}
996
1071
997
1072
/// Suggest wrapping the block in square brackets instead of curly braces
0 commit comments