@@ -61,10 +61,11 @@ use rustc_hir::{self as hir};
61
61
use rustc_macros:: extension;
62
62
use rustc_middle:: bug;
63
63
use rustc_middle:: dep_graph:: DepContext ;
64
+ use rustc_middle:: traits:: PatternOriginExpr ;
64
65
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError , TypeErrorToStringExt } ;
65
66
use rustc_middle:: ty:: print:: { PrintError , PrintTraitRefExt as _, with_forced_trimmed_paths} ;
66
67
use rustc_middle:: ty:: {
67
- self , List , Region , Ty , TyCtxt , TypeFoldable , TypeSuperVisitable , TypeVisitable ,
68
+ self , List , ParamEnv , Region , Ty , TyCtxt , TypeFoldable , TypeSuperVisitable , TypeVisitable ,
68
69
TypeVisitableExt ,
69
70
} ;
70
71
use rustc_span:: { BytePos , DesugaringKind , Pos , Span , sym} ;
@@ -74,7 +75,7 @@ use crate::error_reporting::TypeErrCtxt;
74
75
use crate :: errors:: { ObligationCauseFailureCode , TypeErrorAdditionalDiags } ;
75
76
use crate :: infer;
76
77
use crate :: infer:: relate:: { self , RelateResult , TypeRelation } ;
77
- use crate :: infer:: { InferCtxt , TypeTrace , ValuePairs } ;
78
+ use crate :: infer:: { InferCtxt , InferCtxtExt as _ , TypeTrace , ValuePairs } ;
78
79
use crate :: solve:: deeply_normalize_for_diagnostics;
79
80
use crate :: traits:: {
80
81
IfExpressionCause , MatchExpressionArmCause , ObligationCause , ObligationCauseCode ,
@@ -339,38 +340,71 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
339
340
cause : & ObligationCause < ' tcx > ,
340
341
exp_found : Option < ty:: error:: ExpectedFound < Ty < ' tcx > > > ,
341
342
terr : TypeError < ' tcx > ,
343
+ param_env : Option < ParamEnv < ' tcx > > ,
342
344
) {
343
345
match * cause. code ( ) {
344
- ObligationCauseCode :: Pattern { origin_expr : true , span : Some ( span) , root_ty } => {
345
- let ty = self . resolve_vars_if_possible ( root_ty) ;
346
- if !matches ! ( ty. kind( ) , ty:: Infer ( ty:: InferTy :: TyVar ( _) | ty:: InferTy :: FreshTy ( _) ) )
347
- {
346
+ ObligationCauseCode :: Pattern {
347
+ origin_expr : Some ( origin_expr) ,
348
+ span : Some ( span) ,
349
+ root_ty,
350
+ } => {
351
+ let expected_ty = self . resolve_vars_if_possible ( root_ty) ;
352
+ if !matches ! (
353
+ expected_ty. kind( ) ,
354
+ ty:: Infer ( ty:: InferTy :: TyVar ( _) | ty:: InferTy :: FreshTy ( _) )
355
+ ) {
348
356
// don't show type `_`
349
357
if span. desugaring_kind ( ) == Some ( DesugaringKind :: ForLoop )
350
- && let ty:: Adt ( def, args) = ty . kind ( )
358
+ && let ty:: Adt ( def, args) = expected_ty . kind ( )
351
359
&& Some ( def. did ( ) ) == self . tcx . get_diagnostic_item ( sym:: Option )
352
360
{
353
361
err. span_label (
354
362
span,
355
363
format ! ( "this is an iterator with items of type `{}`" , args. type_at( 0 ) ) ,
356
364
) ;
357
365
} else {
358
- err. span_label ( span, format ! ( "this expression has type `{ty }`" ) ) ;
366
+ err. span_label ( span, format ! ( "this expression has type `{expected_ty }`" ) ) ;
359
367
}
360
368
}
361
369
if let Some ( ty:: error:: ExpectedFound { found, .. } ) = exp_found
362
- && ty . boxed_ty ( ) == Some ( found )
363
- && let Ok ( snippet ) = self . tcx . sess . source_map ( ) . span_to_snippet ( span )
370
+ && let Ok ( mut peeled_snippet ) =
371
+ self . tcx . sess . source_map ( ) . span_to_snippet ( origin_expr . peeled_span )
364
372
{
365
- err. span_suggestion (
366
- span,
367
- "consider dereferencing the boxed value" ,
368
- format ! ( "*{snippet}" ) ,
369
- Applicability :: MachineApplicable ,
370
- ) ;
373
+ // Parentheses are needed for cases like as casts.
374
+ // We use the peeled_span for deref suggestions.
375
+ // It's also safe to use for box, since box only triggers if there
376
+ // wasn't a reference to begin with.
377
+ if origin_expr. peeled_prefix_suggestion_parentheses {
378
+ peeled_snippet = format ! ( "({peeled_snippet})" ) ;
379
+ }
380
+
381
+ // Try giving a box suggestion first, as it is a special case of the
382
+ // deref suggestion.
383
+ if expected_ty. boxed_ty ( ) == Some ( found) {
384
+ err. span_suggestion_verbose (
385
+ span,
386
+ "consider dereferencing the boxed value" ,
387
+ format ! ( "*{peeled_snippet}" ) ,
388
+ Applicability :: MachineApplicable ,
389
+ ) ;
390
+ } else if let Some ( param_env) = param_env
391
+ && let Some ( prefix) = self . should_deref_suggestion_on_mismatch (
392
+ param_env,
393
+ found,
394
+ expected_ty,
395
+ origin_expr,
396
+ )
397
+ {
398
+ err. span_suggestion_verbose (
399
+ span,
400
+ "consider dereferencing to access the inner value using the Deref trait" ,
401
+ format ! ( "{prefix}{peeled_snippet}" ) ,
402
+ Applicability :: MaybeIncorrect ,
403
+ ) ;
404
+ }
371
405
}
372
406
}
373
- ObligationCauseCode :: Pattern { origin_expr : false , span : Some ( span) , .. } => {
407
+ ObligationCauseCode :: Pattern { origin_expr : None , span : Some ( span) , .. } => {
374
408
err. span_label ( span, "expected due to this" ) ;
375
409
}
376
410
ObligationCauseCode :: BlockTailExpression (
@@ -524,6 +558,45 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
524
558
}
525
559
}
526
560
561
+ /// Determines whether deref_to == <deref_from as Deref>::Target, and if so,
562
+ /// returns a prefix that should be added to deref_from as a suggestion.
563
+ fn should_deref_suggestion_on_mismatch (
564
+ & self ,
565
+ param_env : ParamEnv < ' tcx > ,
566
+ deref_to : Ty < ' tcx > ,
567
+ deref_from : Ty < ' tcx > ,
568
+ origin_expr : PatternOriginExpr ,
569
+ ) -> Option < String > {
570
+ // origin_expr contains stripped away versions of our expression.
571
+ // We'll want to use that to avoid suggesting things like *&x.
572
+ // However, the type that we have access to hasn't been stripped away,
573
+ // so we need to ignore the first n dereferences, where n is the number
574
+ // that's been stripped away in origin_expr.
575
+
576
+ // Find a way to autoderef from deraf_from to deref_to.
577
+ let Some ( ( num_derefs, ( after_deref_ty, _) ) ) = ( self . autoderef_steps ) ( deref_from)
578
+ . into_iter ( )
579
+ . enumerate ( )
580
+ . find ( |( _, ( ty, _) ) | self . infcx . can_eq ( param_env, * ty, deref_to) )
581
+ else {
582
+ return None ;
583
+ } ;
584
+
585
+ if num_derefs <= origin_expr. peeled_count {
586
+ return None ;
587
+ }
588
+
589
+ let deref_part = "*" . repeat ( num_derefs - origin_expr. peeled_count ) ;
590
+
591
+ // If the user used a reference in the original expression, they probably
592
+ // want the suggestion to still give a reference.
593
+ if deref_from. is_ref ( ) && !after_deref_ty. is_ref ( ) {
594
+ Some ( format ! ( "&{deref_part}" ) )
595
+ } else {
596
+ Some ( deref_part)
597
+ }
598
+ }
599
+
527
600
/// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
528
601
/// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
529
602
/// populate `other_value` with `other_ty`.
@@ -1312,8 +1385,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
1312
1385
Variable ( ty:: error:: ExpectedFound < Ty < ' a > > ) ,
1313
1386
Fixed ( & ' static str ) ,
1314
1387
}
1315
- let ( expected_found, exp_found, is_simple_error, values) = match values {
1316
- None => ( None , Mismatch :: Fixed ( "type" ) , false , None ) ,
1388
+ let ( expected_found, exp_found, is_simple_error, values, param_env ) = match values {
1389
+ None => ( None , Mismatch :: Fixed ( "type" ) , false , None , None ) ,
1317
1390
Some ( ty:: ParamEnvAnd { param_env, value : values } ) => {
1318
1391
let mut values = self . resolve_vars_if_possible ( values) ;
1319
1392
if self . next_trait_solver ( ) {
@@ -1365,7 +1438,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
1365
1438
diag. downgrade_to_delayed_bug ( ) ;
1366
1439
return ;
1367
1440
} ;
1368
- ( Some ( vals) , exp_found, is_simple_error, Some ( values) )
1441
+ ( Some ( vals) , exp_found, is_simple_error, Some ( values) , Some ( param_env ) )
1369
1442
}
1370
1443
} ;
1371
1444
@@ -1693,7 +1766,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
1693
1766
1694
1767
// It reads better to have the error origin as the final
1695
1768
// thing.
1696
- self . note_error_origin ( diag, cause, exp_found, terr) ;
1769
+ self . note_error_origin ( diag, cause, exp_found, terr, param_env ) ;
1697
1770
1698
1771
debug ! ( ?diag) ;
1699
1772
}
0 commit comments