@@ -64,7 +64,7 @@ use rustc_middle::dep_graph::DepContext;
64
64
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError , TypeErrorToStringExt } ;
65
65
use rustc_middle:: ty:: print:: { PrintError , PrintTraitRefExt as _, with_forced_trimmed_paths} ;
66
66
use rustc_middle:: ty:: {
67
- self , List , Region , Ty , TyCtxt , TypeFoldable , TypeSuperVisitable , TypeVisitable ,
67
+ self , List , ParamEnv , Region , Ty , TyCtxt , TypeFoldable , TypeSuperVisitable , TypeVisitable ,
68
68
TypeVisitableExt ,
69
69
} ;
70
70
use rustc_span:: { BytePos , DesugaringKind , Pos , Span , sym} ;
@@ -74,7 +74,7 @@ use crate::error_reporting::TypeErrCtxt;
74
74
use crate :: errors:: { ObligationCauseFailureCode , TypeErrorAdditionalDiags } ;
75
75
use crate :: infer;
76
76
use crate :: infer:: relate:: { self , RelateResult , TypeRelation } ;
77
- use crate :: infer:: { InferCtxt , TypeTrace , ValuePairs } ;
77
+ use crate :: infer:: { InferCtxt , InferCtxtExt as _ , TypeTrace , ValuePairs } ;
78
78
use crate :: solve:: deeply_normalize_for_diagnostics;
79
79
use crate :: traits:: {
80
80
IfExpressionCause , MatchExpressionArmCause , ObligationCause , ObligationCauseCode ,
@@ -339,9 +339,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
339
339
cause : & ObligationCause < ' tcx > ,
340
340
exp_found : Option < ty:: error:: ExpectedFound < Ty < ' tcx > > > ,
341
341
terr : TypeError < ' tcx > ,
342
+ param_env : Option < ParamEnv < ' tcx > > ,
342
343
) {
343
344
match * cause. code ( ) {
344
- ObligationCauseCode :: Pattern { origin_expr : true , span : Some ( span) , root_ty } => {
345
+ ObligationCauseCode :: Pattern {
346
+ origin_expr : true ,
347
+ span : Some ( span) ,
348
+ root_ty,
349
+ prefix_suggestion_parentheses,
350
+ } => {
345
351
let ty = self . resolve_vars_if_possible ( root_ty) ;
346
352
if !matches ! ( ty. kind( ) , ty:: Infer ( ty:: InferTy :: TyVar ( _) | ty:: InferTy :: FreshTy ( _) ) )
347
353
{
@@ -358,16 +364,39 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
358
364
err. span_label ( span, format ! ( "this expression has type `{ty}`" ) ) ;
359
365
}
360
366
}
361
- 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)
364
- {
365
- err. span_suggestion (
366
- span,
367
- "consider dereferencing the boxed value" ,
368
- format ! ( "*{snippet}" ) ,
369
- Applicability :: MachineApplicable ,
370
- ) ;
367
+ if let Some ( ty:: error:: ExpectedFound { found, .. } ) = exp_found {
368
+ // Parentheses are needed for cases like as casts.
369
+ let mut snippet = if prefix_suggestion_parentheses {
370
+ vec ! [
371
+ ( span. shrink_to_lo( ) , "(" . to_string( ) ) ,
372
+ ( span. shrink_to_hi( ) , ")" . to_string( ) ) ,
373
+ ]
374
+ } else {
375
+ vec ! [ ( span. shrink_to_lo( ) , "" . to_string( ) ) ]
376
+ } ;
377
+
378
+ // Try giving a box suggestion first, as it is a special case of the
379
+ // deref suggestion.
380
+ if ty. boxed_ty ( ) == Some ( found) {
381
+ snippet[ 0 ] . 1 = "*" . to_string ( ) + & snippet[ 0 ] . 1 ;
382
+
383
+ err. multipart_suggestion_verbose (
384
+ "consider dereferencing the boxed value" ,
385
+ snippet,
386
+ Applicability :: MachineApplicable ,
387
+ ) ;
388
+ } else if let Some ( param_env) = param_env
389
+ && let Some ( prefix) =
390
+ self . should_deref_suggestion_on_mismatch ( param_env, found, ty)
391
+ {
392
+ snippet[ 0 ] . 1 = prefix + & snippet[ 0 ] . 1 ;
393
+
394
+ err. multipart_suggestion_verbose (
395
+ "consider dereferencing to access the inner value" ,
396
+ snippet,
397
+ Applicability :: MaybeIncorrect ,
398
+ ) ;
399
+ }
371
400
}
372
401
}
373
402
ObligationCauseCode :: Pattern { origin_expr : false , span : Some ( span) , .. } => {
@@ -524,6 +553,38 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
524
553
}
525
554
}
526
555
556
+ /// Determines whether deref_to == <deref_from as Deref>::Target, and if so,
557
+ /// returns a prefix that should be added to deref_from as a suggestion.
558
+ fn should_deref_suggestion_on_mismatch (
559
+ & self ,
560
+ param_env : ParamEnv < ' tcx > ,
561
+ deref_to : Ty < ' tcx > ,
562
+ deref_from : Ty < ' tcx > ,
563
+ ) -> Option < String > {
564
+ // Find a way to autoderef from deraf_from to deref_to.
565
+ let Some ( ( num_derefs, ( after_deref_ty, _) ) ) = ( self . autoderef_steps ) ( deref_from)
566
+ . into_iter ( )
567
+ . enumerate ( )
568
+ . find ( |( _, ( ty, _) ) | self . infcx . can_eq ( param_env, * ty, deref_to) )
569
+ else {
570
+ return None ;
571
+ } ;
572
+
573
+ if num_derefs == 0 {
574
+ return None ;
575
+ }
576
+
577
+ let deref_part = "*" . repeat ( num_derefs) ;
578
+
579
+ // Try to give a suggestion with the same type of reference/non-reference as the original code.
580
+ // For example, if deref_from was a reference, then make the suggestion a reference as well.
581
+ if deref_from. is_ref ( ) && !after_deref_ty. is_ref ( ) {
582
+ Some ( format ! ( "&{deref_part}" ) )
583
+ } else {
584
+ Some ( deref_part)
585
+ }
586
+ }
587
+
527
588
/// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
528
589
/// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
529
590
/// populate `other_value` with `other_ty`.
@@ -1312,8 +1373,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
1312
1373
Variable ( ty:: error:: ExpectedFound < Ty < ' a > > ) ,
1313
1374
Fixed ( & ' static str ) ,
1314
1375
}
1315
- let ( expected_found, exp_found, is_simple_error, values) = match values {
1316
- None => ( None , Mismatch :: Fixed ( "type" ) , false , None ) ,
1376
+ let ( expected_found, exp_found, is_simple_error, values, param_env ) = match values {
1377
+ None => ( None , Mismatch :: Fixed ( "type" ) , false , None , None ) ,
1317
1378
Some ( ty:: ParamEnvAnd { param_env, value : values } ) => {
1318
1379
let mut values = self . resolve_vars_if_possible ( values) ;
1319
1380
if self . next_trait_solver ( ) {
@@ -1365,7 +1426,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
1365
1426
diag. downgrade_to_delayed_bug ( ) ;
1366
1427
return ;
1367
1428
} ;
1368
- ( Some ( vals) , exp_found, is_simple_error, Some ( values) )
1429
+ ( Some ( vals) , exp_found, is_simple_error, Some ( values) , Some ( param_env ) )
1369
1430
}
1370
1431
} ;
1371
1432
@@ -1693,7 +1754,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
1693
1754
1694
1755
// It reads better to have the error origin as the final
1695
1756
// thing.
1696
- self . note_error_origin ( diag, cause, exp_found, terr) ;
1757
+ self . note_error_origin ( diag, cause, exp_found, terr, param_env ) ;
1697
1758
1698
1759
debug ! ( ?diag) ;
1699
1760
}
0 commit comments