@@ -63,10 +63,11 @@ use rustc_hir::{self as hir};
63
63
use rustc_macros:: extension;
64
64
use rustc_middle:: bug;
65
65
use rustc_middle:: dep_graph:: DepContext ;
66
+ use rustc_middle:: traits:: PatternOriginExpr ;
66
67
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError , TypeErrorToStringExt } ;
67
68
use rustc_middle:: ty:: print:: { PrintError , PrintTraitRefExt as _, with_forced_trimmed_paths} ;
68
69
use rustc_middle:: ty:: {
69
- self , List , Region , Ty , TyCtxt , TypeFoldable , TypeSuperVisitable , TypeVisitable ,
70
+ self , List , ParamEnv , Region , Ty , TyCtxt , TypeFoldable , TypeSuperVisitable , TypeVisitable ,
70
71
TypeVisitableExt ,
71
72
} ;
72
73
use rustc_span:: def_id:: LOCAL_CRATE ;
@@ -77,7 +78,7 @@ use crate::error_reporting::TypeErrCtxt;
77
78
use crate :: errors:: { ObligationCauseFailureCode , TypeErrorAdditionalDiags } ;
78
79
use crate :: infer;
79
80
use crate :: infer:: relate:: { self , RelateResult , TypeRelation } ;
80
- use crate :: infer:: { InferCtxt , TypeTrace , ValuePairs } ;
81
+ use crate :: infer:: { InferCtxt , InferCtxtExt as _ , TypeTrace , ValuePairs } ;
81
82
use crate :: solve:: deeply_normalize_for_diagnostics;
82
83
use crate :: traits:: {
83
84
IfExpressionCause , MatchExpressionArmCause , ObligationCause , ObligationCauseCode ,
@@ -433,38 +434,71 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
433
434
cause : & ObligationCause < ' tcx > ,
434
435
exp_found : Option < ty:: error:: ExpectedFound < Ty < ' tcx > > > ,
435
436
terr : TypeError < ' tcx > ,
437
+ param_env : Option < ParamEnv < ' tcx > > ,
436
438
) {
437
439
match * cause. code ( ) {
438
- ObligationCauseCode :: Pattern { origin_expr : true , span : Some ( span) , root_ty } => {
439
- let ty = self . resolve_vars_if_possible ( root_ty) ;
440
- if !matches ! ( ty. kind( ) , ty:: Infer ( ty:: InferTy :: TyVar ( _) | ty:: InferTy :: FreshTy ( _) ) )
441
- {
440
+ ObligationCauseCode :: Pattern {
441
+ origin_expr : Some ( origin_expr) ,
442
+ span : Some ( span) ,
443
+ root_ty,
444
+ } => {
445
+ let expected_ty = self . resolve_vars_if_possible ( root_ty) ;
446
+ if !matches ! (
447
+ expected_ty. kind( ) ,
448
+ ty:: Infer ( ty:: InferTy :: TyVar ( _) | ty:: InferTy :: FreshTy ( _) )
449
+ ) {
442
450
// don't show type `_`
443
451
if span. desugaring_kind ( ) == Some ( DesugaringKind :: ForLoop )
444
- && let ty:: Adt ( def, args) = ty . kind ( )
452
+ && let ty:: Adt ( def, args) = expected_ty . kind ( )
445
453
&& Some ( def. did ( ) ) == self . tcx . get_diagnostic_item ( sym:: Option )
446
454
{
447
455
err. span_label (
448
456
span,
449
457
format ! ( "this is an iterator with items of type `{}`" , args. type_at( 0 ) ) ,
450
458
) ;
451
459
} else {
452
- err. span_label ( span, format ! ( "this expression has type `{ty }`" ) ) ;
460
+ err. span_label ( span, format ! ( "this expression has type `{expected_ty }`" ) ) ;
453
461
}
454
462
}
455
463
if let Some ( ty:: error:: ExpectedFound { found, .. } ) = exp_found
456
- && ty . boxed_ty ( ) == Some ( found )
457
- && let Ok ( snippet ) = self . tcx . sess . source_map ( ) . span_to_snippet ( span )
464
+ && let Ok ( mut peeled_snippet ) =
465
+ self . tcx . sess . source_map ( ) . span_to_snippet ( origin_expr . peeled_span )
458
466
{
459
- err. span_suggestion (
460
- span,
461
- "consider dereferencing the boxed value" ,
462
- format ! ( "*{snippet}" ) ,
463
- Applicability :: MachineApplicable ,
464
- ) ;
467
+ // Parentheses are needed for cases like as casts.
468
+ // We use the peeled_span for deref suggestions.
469
+ // It's also safe to use for box, since box only triggers if there
470
+ // wasn't a reference to begin with.
471
+ if origin_expr. peeled_prefix_suggestion_parentheses {
472
+ peeled_snippet = format ! ( "({peeled_snippet})" ) ;
473
+ }
474
+
475
+ // Try giving a box suggestion first, as it is a special case of the
476
+ // deref suggestion.
477
+ if expected_ty. boxed_ty ( ) == Some ( found) {
478
+ err. span_suggestion_verbose (
479
+ span,
480
+ "consider dereferencing the boxed value" ,
481
+ format ! ( "*{peeled_snippet}" ) ,
482
+ Applicability :: MachineApplicable ,
483
+ ) ;
484
+ } else if let Some ( param_env) = param_env
485
+ && let Some ( prefix) = self . should_deref_suggestion_on_mismatch (
486
+ param_env,
487
+ found,
488
+ expected_ty,
489
+ origin_expr,
490
+ )
491
+ {
492
+ err. span_suggestion_verbose (
493
+ span,
494
+ "consider dereferencing to access the inner value using the Deref trait" ,
495
+ format ! ( "{prefix}{peeled_snippet}" ) ,
496
+ Applicability :: MaybeIncorrect ,
497
+ ) ;
498
+ }
465
499
}
466
500
}
467
- ObligationCauseCode :: Pattern { origin_expr : false , span : Some ( span) , .. } => {
501
+ ObligationCauseCode :: Pattern { origin_expr : None , span : Some ( span) , .. } => {
468
502
err. span_label ( span, "expected due to this" ) ;
469
503
}
470
504
ObligationCauseCode :: BlockTailExpression (
@@ -618,6 +652,45 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
618
652
}
619
653
}
620
654
655
+ /// Determines whether deref_to == <deref_from as Deref>::Target, and if so,
656
+ /// returns a prefix that should be added to deref_from as a suggestion.
657
+ fn should_deref_suggestion_on_mismatch (
658
+ & self ,
659
+ param_env : ParamEnv < ' tcx > ,
660
+ deref_to : Ty < ' tcx > ,
661
+ deref_from : Ty < ' tcx > ,
662
+ origin_expr : PatternOriginExpr ,
663
+ ) -> Option < String > {
664
+ // origin_expr contains stripped away versions of our expression.
665
+ // We'll want to use that to avoid suggesting things like *&x.
666
+ // However, the type that we have access to hasn't been stripped away,
667
+ // so we need to ignore the first n dereferences, where n is the number
668
+ // that's been stripped away in origin_expr.
669
+
670
+ // Find a way to autoderef from deref_from to deref_to.
671
+ let Some ( ( num_derefs, ( after_deref_ty, _) ) ) = ( self . autoderef_steps ) ( deref_from)
672
+ . into_iter ( )
673
+ . enumerate ( )
674
+ . find ( |( _, ( ty, _) ) | self . infcx . can_eq ( param_env, * ty, deref_to) )
675
+ else {
676
+ return None ;
677
+ } ;
678
+
679
+ if num_derefs <= origin_expr. peeled_count {
680
+ return None ;
681
+ }
682
+
683
+ let deref_part = "*" . repeat ( num_derefs - origin_expr. peeled_count ) ;
684
+
685
+ // If the user used a reference in the original expression, they probably
686
+ // want the suggestion to still give a reference.
687
+ if deref_from. is_ref ( ) && !after_deref_ty. is_ref ( ) {
688
+ Some ( format ! ( "&{deref_part}" ) )
689
+ } else {
690
+ Some ( deref_part)
691
+ }
692
+ }
693
+
621
694
/// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
622
695
/// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
623
696
/// populate `other_value` with `other_ty`.
@@ -1406,8 +1479,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
1406
1479
Variable ( ty:: error:: ExpectedFound < Ty < ' a > > ) ,
1407
1480
Fixed ( & ' static str ) ,
1408
1481
}
1409
- let ( expected_found, exp_found, is_simple_error, values) = match values {
1410
- None => ( None , Mismatch :: Fixed ( "type" ) , false , None ) ,
1482
+ let ( expected_found, exp_found, is_simple_error, values, param_env ) = match values {
1483
+ None => ( None , Mismatch :: Fixed ( "type" ) , false , None , None ) ,
1411
1484
Some ( ty:: ParamEnvAnd { param_env, value : values } ) => {
1412
1485
let mut values = self . resolve_vars_if_possible ( values) ;
1413
1486
if self . next_trait_solver ( ) {
@@ -1459,7 +1532,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
1459
1532
diag. downgrade_to_delayed_bug ( ) ;
1460
1533
return ;
1461
1534
} ;
1462
- ( Some ( vals) , exp_found, is_simple_error, Some ( values) )
1535
+ ( Some ( vals) , exp_found, is_simple_error, Some ( values) , Some ( param_env ) )
1463
1536
}
1464
1537
} ;
1465
1538
@@ -1791,7 +1864,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
1791
1864
1792
1865
// It reads better to have the error origin as the final
1793
1866
// thing.
1794
- self . note_error_origin ( diag, cause, exp_found, terr) ;
1867
+ self . note_error_origin ( diag, cause, exp_found, terr, param_env ) ;
1795
1868
1796
1869
debug ! ( ?diag) ;
1797
1870
}
0 commit comments