1
1
use crate :: check:: FnCtxt ;
2
2
use rustc_infer:: infer:: InferOk ;
3
+ use rustc_middle:: middle:: stability:: EvalResult ;
3
4
use rustc_trait_selection:: infer:: InferCtxtExt as _;
4
5
use rustc_trait_selection:: traits:: ObligationCause ;
5
6
@@ -363,18 +364,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
363
364
}
364
365
}
365
366
366
- let compatible_variants: Vec < ( String , Option < String > ) > = expected_adt
367
+ let compatible_variants: Vec < ( String , _ , _ , Option < String > ) > = expected_adt
367
368
. variants ( )
368
369
. iter ( )
369
370
. filter ( |variant| {
370
- variant. fields . len ( ) == 1 && variant . ctor_kind == hir :: def :: CtorKind :: Fn
371
+ variant. fields . len ( ) == 1
371
372
} )
372
373
. filter_map ( |variant| {
373
374
let sole_field = & variant. fields [ 0 ] ;
374
375
375
376
let field_is_local = sole_field. did . is_local ( ) ;
376
377
let field_is_accessible =
377
- sole_field. vis . is_accessible_from ( expr. hir_id . owner . to_def_id ( ) , self . tcx ) ;
378
+ sole_field. vis . is_accessible_from ( expr. hir_id . owner . to_def_id ( ) , self . tcx )
379
+ // Skip suggestions for unstable public fields (for example `Pin::pointer`)
380
+ && matches ! ( self . tcx. eval_stability( sole_field. did, None , expr. span, None ) , EvalResult :: Allow | EvalResult :: Unmarked ) ;
378
381
379
382
if !field_is_local && !field_is_accessible {
380
383
return None ;
@@ -391,33 +394,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
391
394
if let Some ( path) = variant_path. strip_prefix ( "std::prelude::" )
392
395
&& let Some ( ( _, path) ) = path. split_once ( "::" )
393
396
{
394
- return Some ( ( path. to_string ( ) , note_about_variant_field_privacy) ) ;
397
+ return Some ( ( path. to_string ( ) , variant . ctor_kind , sole_field . name , note_about_variant_field_privacy) ) ;
395
398
}
396
- Some ( ( variant_path, note_about_variant_field_privacy) )
399
+ Some ( ( variant_path, variant . ctor_kind , sole_field . name , note_about_variant_field_privacy) )
397
400
} else {
398
401
None
399
402
}
400
403
} )
401
404
. collect ( ) ;
402
405
403
- let prefix = match self . maybe_get_struct_pattern_shorthand_field ( expr) {
404
- Some ( ident) => format ! ( "{ident}: " ) ,
405
- None => String :: new ( ) ,
406
+ let suggestions_for = |variant : & _ , ctor, field_name| {
407
+ let prefix = match self . maybe_get_struct_pattern_shorthand_field ( expr) {
408
+ Some ( ident) => format ! ( "{ident}: " ) ,
409
+ None => String :: new ( ) ,
410
+ } ;
411
+
412
+ let ( open, close) = match ctor {
413
+ hir:: def:: CtorKind :: Fn => ( "(" . to_owned ( ) , ")" ) ,
414
+ hir:: def:: CtorKind :: Fictive => ( format ! ( " {{ {field_name}: " ) , " }" ) ,
415
+
416
+ // unit variants don't have fields
417
+ hir:: def:: CtorKind :: Const => unreachable ! ( ) ,
418
+ } ;
419
+
420
+ vec ! [
421
+ ( expr. span. shrink_to_lo( ) , format!( "{prefix}{variant}{open}" ) ) ,
422
+ ( expr. span. shrink_to_hi( ) , close. to_owned( ) ) ,
423
+ ]
406
424
} ;
407
425
408
426
match & compatible_variants[ ..] {
409
427
[ ] => { /* No variants to format */ }
410
- [ ( variant, note) ] => {
428
+ [ ( variant, ctor_kind , field_name , note) ] => {
411
429
// Just a single matching variant.
412
430
err. multipart_suggestion_verbose (
413
431
& format ! (
414
432
"try wrapping the expression in `{variant}`{note}" ,
415
433
note = note. as_deref( ) . unwrap_or( "" )
416
434
) ,
417
- vec ! [
418
- ( expr. span. shrink_to_lo( ) , format!( "{prefix}{variant}(" ) ) ,
419
- ( expr. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
420
- ] ,
435
+ suggestions_for ( & * * variant, * ctor_kind, * field_name) ,
421
436
Applicability :: MaybeIncorrect ,
422
437
) ;
423
438
}
@@ -428,12 +443,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
428
443
"try wrapping the expression in a variant of `{}`" ,
429
444
self . tcx. def_path_str( expected_adt. did( ) )
430
445
) ,
431
- compatible_variants. into_iter ( ) . map ( |( variant, _) | {
432
- vec ! [
433
- ( expr. span. shrink_to_lo( ) , format!( "{prefix}{variant}(" ) ) ,
434
- ( expr. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
435
- ]
436
- } ) ,
446
+ compatible_variants. into_iter ( ) . map (
447
+ |( variant, ctor_kind, field_name, _) | {
448
+ suggestions_for ( & variant, ctor_kind, field_name)
449
+ } ,
450
+ ) ,
437
451
Applicability :: MaybeIncorrect ,
438
452
) ;
439
453
}
0 commit comments