@@ -33,6 +33,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
33
33
self . annotate_expected_due_to_let_ty ( err, expr, error) ;
34
34
self . suggest_deref_ref_or_into ( err, expr, expected, expr_ty, expected_ty_expr) ;
35
35
self . suggest_compatible_variants ( err, expr, expected, expr_ty) ;
36
+ self . suggest_non_zero_new_unwrap ( err, expr, expected, expr_ty) ;
36
37
if self . suggest_calling_boxed_future_when_appropriate ( err, expr, expected, expr_ty) {
37
38
return ;
38
39
}
@@ -347,14 +348,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
347
348
}
348
349
}
349
350
350
- let compatible_variants: Vec < String > = expected_adt
351
+ let compatible_variants: Vec < ( String , Option < String > ) > = expected_adt
351
352
. variants ( )
352
353
. iter ( )
353
354
. filter ( |variant| {
354
355
variant. fields . len ( ) == 1 && variant. ctor_kind == hir:: def:: CtorKind :: Fn
355
356
} )
356
357
. filter_map ( |variant| {
357
358
let sole_field = & variant. fields [ 0 ] ;
359
+
360
+ let field_is_local = sole_field. did . is_local ( ) ;
361
+ let field_is_accessible =
362
+ sole_field. vis . is_accessible_from ( expr. hir_id . owner . to_def_id ( ) , self . tcx ) ;
363
+
364
+ if !field_is_local && !field_is_accessible {
365
+ return None ;
366
+ }
367
+
368
+ let note_about_variant_field_privacy = ( field_is_local && !field_is_accessible)
369
+ . then ( || format ! ( " (its field is private, but it's local to this crate and its privacy can be changed)" ) ) ;
370
+
358
371
let sole_field_ty = sole_field. ty ( self . tcx , substs) ;
359
372
if self . can_coerce ( expr_ty, sole_field_ty) {
360
373
let variant_path =
@@ -363,9 +376,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
363
376
if let Some ( path) = variant_path. strip_prefix ( "std::prelude::" )
364
377
&& let Some ( ( _, path) ) = path. split_once ( "::" )
365
378
{
366
- return Some ( path. to_string ( ) ) ;
379
+ return Some ( ( path. to_string ( ) , note_about_variant_field_privacy ) ) ;
367
380
}
368
- Some ( variant_path)
381
+ Some ( ( variant_path, note_about_variant_field_privacy ) )
369
382
} else {
370
383
None
371
384
}
@@ -379,10 +392,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
379
392
380
393
match & compatible_variants[ ..] {
381
394
[ ] => { /* No variants to format */ }
382
- [ variant] => {
395
+ [ ( variant, note ) ] => {
383
396
// Just a single matching variant.
384
397
err. multipart_suggestion_verbose (
385
- & format ! ( "try wrapping the expression in `{variant}`" ) ,
398
+ & format ! (
399
+ "try wrapping the expression in `{variant}`{note}" ,
400
+ note = note. as_deref( ) . unwrap_or( "" )
401
+ ) ,
386
402
vec ! [
387
403
( expr. span. shrink_to_lo( ) , format!( "{prefix}{variant}(" ) ) ,
388
404
( expr. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
@@ -397,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
397
413
"try wrapping the expression in a variant of `{}`" ,
398
414
self . tcx. def_path_str( expected_adt. did( ) )
399
415
) ,
400
- compatible_variants. into_iter ( ) . map ( |variant| {
416
+ compatible_variants. into_iter ( ) . map ( |( variant, _ ) | {
401
417
vec ! [
402
418
( expr. span. shrink_to_lo( ) , format!( "{prefix}{variant}(" ) ) ,
403
419
( expr. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
@@ -410,6 +426,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
410
426
}
411
427
}
412
428
429
+ fn suggest_non_zero_new_unwrap (
430
+ & self ,
431
+ err : & mut Diagnostic ,
432
+ expr : & hir:: Expr < ' _ > ,
433
+ expected : Ty < ' tcx > ,
434
+ expr_ty : Ty < ' tcx > ,
435
+ ) {
436
+ let tcx = self . tcx ;
437
+ let ( adt, unwrap) = match expected. kind ( ) {
438
+ // In case Option<NonZero*> is wanted, but * is provided, suggest calling new
439
+ ty:: Adt ( adt, substs) if tcx. is_diagnostic_item ( sym:: Option , adt. did ( ) ) => {
440
+ // Unwrap option
441
+ let ty:: Adt ( adt, _) = substs. type_at ( 0 ) . kind ( ) else { return } ;
442
+
443
+ ( adt, "" )
444
+ }
445
+ // In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types
446
+ ty:: Adt ( adt, _) => ( adt, ".unwrap()" ) ,
447
+ _ => return ,
448
+ } ;
449
+
450
+ let map = [
451
+ ( sym:: NonZeroU8 , tcx. types . u8 ) ,
452
+ ( sym:: NonZeroU16 , tcx. types . u16 ) ,
453
+ ( sym:: NonZeroU32 , tcx. types . u32 ) ,
454
+ ( sym:: NonZeroU64 , tcx. types . u64 ) ,
455
+ ( sym:: NonZeroU128 , tcx. types . u128 ) ,
456
+ ( sym:: NonZeroI8 , tcx. types . i8 ) ,
457
+ ( sym:: NonZeroI16 , tcx. types . i16 ) ,
458
+ ( sym:: NonZeroI32 , tcx. types . i32 ) ,
459
+ ( sym:: NonZeroI64 , tcx. types . i64 ) ,
460
+ ( sym:: NonZeroI128 , tcx. types . i128 ) ,
461
+ ] ;
462
+
463
+ let Some ( ( s, _) ) = map
464
+ . iter ( )
465
+ . find ( |& & ( s, t) | self . tcx . is_diagnostic_item ( s, adt. did ( ) ) && self . can_coerce ( expr_ty, t) )
466
+ else { return } ;
467
+
468
+ let path = self . tcx . def_path_str ( adt. non_enum_variant ( ) . def_id ) ;
469
+
470
+ err. multipart_suggestion (
471
+ format ! ( "consider calling `{s}::new`" ) ,
472
+ vec ! [
473
+ ( expr. span. shrink_to_lo( ) , format!( "{path}::new(" ) ) ,
474
+ ( expr. span. shrink_to_hi( ) , format!( "){unwrap}" ) ) ,
475
+ ] ,
476
+ Applicability :: MaybeIncorrect ,
477
+ ) ;
478
+ }
479
+
413
480
pub fn get_conversion_methods (
414
481
& self ,
415
482
span : Span ,
0 commit comments