@@ -13,12 +13,19 @@ use rustc_span::{sym, BytePos, Span};
13
13
use rustc_target:: abi:: FieldIdx ;
14
14
15
15
use crate :: errors:: {
16
- ConsiderAddingAwait , FnItemsAreDistinct , FunctionPointerSuggestion , SuggAddLetForLetChains ,
16
+ ConsiderAddingAwait , DiagArg , FnConsiderCasting , FnItemsAreDistinct , FnUniqTypes ,
17
+ FunctionPointerSuggestion , SuggAddLetForLetChains , SuggestAsRefWhereAppropriate ,
17
18
SuggestRemoveSemiOrReturnBinding ,
18
19
} ;
19
20
20
21
use super :: TypeErrCtxt ;
21
22
23
+ #[ derive( Clone , Copy ) ]
24
+ pub enum SuggestAsRefKind {
25
+ Option ,
26
+ Result ,
27
+ }
28
+
22
29
impl < ' tcx > TypeErrCtxt < ' _ , ' tcx > {
23
30
pub ( super ) fn suggest_remove_semi_or_return_binding (
24
31
& self ,
@@ -322,15 +329,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
322
329
diag : & mut Diagnostic ,
323
330
) {
324
331
if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span)
325
- && let Some ( msg) = self . should_suggest_as_ref ( exp_found. expected , exp_found. found )
332
+ && let Some ( msg) = self . should_suggest_as_ref_kind ( exp_found. expected , exp_found. found )
326
333
{
327
- diag . span_suggestion (
328
- span ,
329
- msg,
330
- // HACK: fix issue# 100605, suggesting convert from & Option<T> to Option<&T>, remove the extra `&`
331
- format ! ( "{}.as_ref()" , snippet. trim_start_matches ( '&' ) ) ,
332
- Applicability :: MachineApplicable ,
333
- ) ;
334
+ // HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
335
+ let snippet = snippet . trim_start_matches ( '&' ) ;
336
+ let subdiag = match msg {
337
+ SuggestAsRefKind :: Option => SuggestAsRefWhereAppropriate :: Option { span , snippet } ,
338
+ SuggestAsRefKind :: Result => SuggestAsRefWhereAppropriate :: Result { span , snippet } ,
339
+ } ;
340
+ diag . subdiagnostic ( subdiag ) ;
334
341
}
335
342
}
336
343
@@ -384,7 +391,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
384
391
& ( self . normalize_fn_sig ) ( self . tcx . fn_sig ( * did2) . subst ( self . tcx , substs2) ) ;
385
392
386
393
if self . same_type_modulo_infer ( * expected_sig, * found_sig) {
387
- diag. note ( "different fn items have unique types, even if their signatures are the same" ) ;
394
+ diag. subdiagnostic ( FnUniqTypes ) ;
388
395
}
389
396
390
397
if !self . same_type_modulo_infer ( * found_sig, * expected_sig)
@@ -398,16 +405,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
398
405
399
406
let fn_name = self . tcx . def_path_str_with_substs ( * did2, substs2) ;
400
407
let sug = if found. is_ref ( ) {
401
- format ! ( "&({fn_name} as {found_sig})" )
408
+ FunctionPointerSuggestion :: CastBothRef {
409
+ span,
410
+ fn_name,
411
+ found_sig : * found_sig,
412
+ expected_sig : DiagArg ( * expected_sig) ,
413
+ }
402
414
} else {
403
- format ! ( "{fn_name} as {found_sig}" )
415
+ FunctionPointerSuggestion :: CastBoth {
416
+ span,
417
+ fn_name,
418
+ found_sig : * found_sig,
419
+ expected_sig : DiagArg ( * expected_sig) ,
420
+ }
404
421
} ;
405
422
406
- let msg = format ! (
407
- "consider casting both fn items to fn pointers using `as {expected_sig}`"
408
- ) ;
409
-
410
- diag. span_suggestion_hidden ( span, msg, sug, Applicability :: MaybeIncorrect ) ;
423
+ diag. subdiagnostic ( sug) ;
411
424
}
412
425
( ty:: FnDef ( did, substs) , ty:: FnPtr ( sig) ) => {
413
426
let expected_sig =
@@ -426,31 +439,27 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
426
439
format ! ( "{fn_name} as {found_sig}" )
427
440
} ;
428
441
429
- diag. help ( & format ! ( "consider casting the fn item to a fn pointer: `{}`" , casting) ) ;
442
+ diag. subdiagnostic ( FnConsiderCasting { casting } ) ;
430
443
}
431
444
_ => {
432
445
return ;
433
446
}
434
447
} ;
435
448
}
436
449
437
- pub fn should_suggest_as_ref ( & self , expected : Ty < ' tcx > , found : Ty < ' tcx > ) -> Option < & str > {
450
+ pub fn should_suggest_as_ref_kind (
451
+ & self ,
452
+ expected : Ty < ' tcx > ,
453
+ found : Ty < ' tcx > ,
454
+ ) -> Option < SuggestAsRefKind > {
438
455
if let ( ty:: Adt ( exp_def, exp_substs) , ty:: Ref ( _, found_ty, _) ) =
439
456
( expected. kind ( ) , found. kind ( ) )
440
457
{
441
458
if let ty:: Adt ( found_def, found_substs) = * found_ty. kind ( ) {
442
459
if exp_def == & found_def {
443
460
let have_as_ref = & [
444
- (
445
- sym:: Option ,
446
- "you can convert from `&Option<T>` to `Option<&T>` using \
447
- `.as_ref()`",
448
- ) ,
449
- (
450
- sym:: Result ,
451
- "you can convert from `&Result<T, E>` to \
452
- `Result<&T, &E>` using `.as_ref()`",
453
- ) ,
461
+ ( sym:: Option , SuggestAsRefKind :: Option ) ,
462
+ ( sym:: Result , SuggestAsRefKind :: Result ) ,
454
463
] ;
455
464
if let Some ( msg) = have_as_ref. iter ( ) . find_map ( |( name, msg) | {
456
465
self . tcx . is_diagnostic_item ( * name, exp_def. did ( ) ) . then_some ( msg)
@@ -484,6 +493,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
484
493
None
485
494
}
486
495
496
+ // FIXME: Remove once rustc_hir_typeck is migrated to Diagnostics
497
+ pub fn should_suggest_as_ref ( & self , expected : Ty < ' tcx > , found : Ty < ' tcx > ) -> Option < & str > {
498
+ match self . should_suggest_as_ref_kind ( expected, found) {
499
+ Some ( SuggestAsRefKind :: Option ) => Some (
500
+ "you can convert from `&Option<T>` to `Option<&T>` using \
501
+ `.as_ref()`",
502
+ ) ,
503
+ Some ( SuggestAsRefKind :: Result ) => Some (
504
+ "you can convert from `&Result<T, E>` to \
505
+ `Result<&T, &E>` using `.as_ref()`",
506
+ ) ,
507
+ None => None ,
508
+ }
509
+ }
487
510
/// Try to find code with pattern `if Some(..) = expr`
488
511
/// use a `visitor` to mark the `if` which its span contains given error span,
489
512
/// and then try to find a assignment in the `cond` part, which span is equal with error span
0 commit comments