1
1
use std:: cell:: OnceCell ;
2
+ use std:: ops:: ControlFlow ;
2
3
4
+ use rustc_data_structures:: fx:: FxHashSet ;
3
5
use rustc_data_structures:: graph:: iterate:: DepthFirstSearch ;
4
6
use rustc_data_structures:: graph:: vec_graph:: VecGraph ;
5
7
use rustc_data_structures:: graph:: { self } ;
@@ -321,7 +323,11 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
321
323
let mut diverging_fallback = UnordMap :: with_capacity ( diverging_vids. len ( ) ) ;
322
324
let unsafe_infer_vars = OnceCell :: new ( ) ;
323
325
324
- self . lint_obligations_broken_by_never_type_fallback_change ( behavior, & diverging_vids) ;
326
+ self . lint_obligations_broken_by_never_type_fallback_change (
327
+ behavior,
328
+ & diverging_vids,
329
+ & coercion_graph,
330
+ ) ;
325
331
326
332
for & diverging_vid in & diverging_vids {
327
333
let diverging_ty = Ty :: new_var ( self . tcx , diverging_vid) ;
@@ -429,19 +435,31 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
429
435
. filter_map ( |x| unsafe_infer_vars. get ( & x) . copied ( ) )
430
436
. collect :: < Vec < _ > > ( ) ;
431
437
438
+ let sugg = self . try_to_suggest_annotations ( & [ root_vid] , coercion_graph) ;
439
+
432
440
for ( hir_id, span, reason) in affected_unsafe_infer_vars {
433
441
self . tcx . emit_node_span_lint (
434
442
lint:: builtin:: NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE ,
435
443
hir_id,
436
444
span,
437
445
match reason {
438
- UnsafeUseReason :: Call => errors:: NeverTypeFallbackFlowingIntoUnsafe :: Call ,
439
- UnsafeUseReason :: Method => errors:: NeverTypeFallbackFlowingIntoUnsafe :: Method ,
440
- UnsafeUseReason :: Path => errors:: NeverTypeFallbackFlowingIntoUnsafe :: Path ,
446
+ UnsafeUseReason :: Call => {
447
+ errors:: NeverTypeFallbackFlowingIntoUnsafe :: Call { sugg : sugg. clone ( ) }
448
+ }
449
+ UnsafeUseReason :: Method => {
450
+ errors:: NeverTypeFallbackFlowingIntoUnsafe :: Method { sugg : sugg. clone ( ) }
451
+ }
452
+ UnsafeUseReason :: Path => {
453
+ errors:: NeverTypeFallbackFlowingIntoUnsafe :: Path { sugg : sugg. clone ( ) }
454
+ }
441
455
UnsafeUseReason :: UnionField => {
442
- errors:: NeverTypeFallbackFlowingIntoUnsafe :: UnionField
456
+ errors:: NeverTypeFallbackFlowingIntoUnsafe :: UnionField {
457
+ sugg : sugg. clone ( ) ,
458
+ }
459
+ }
460
+ UnsafeUseReason :: Deref => {
461
+ errors:: NeverTypeFallbackFlowingIntoUnsafe :: Deref { sugg : sugg. clone ( ) }
443
462
}
444
- UnsafeUseReason :: Deref => errors:: NeverTypeFallbackFlowingIntoUnsafe :: Deref ,
445
463
} ,
446
464
) ;
447
465
}
@@ -451,6 +469,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
451
469
& self ,
452
470
behavior : DivergingFallbackBehavior ,
453
471
diverging_vids : & [ ty:: TyVid ] ,
472
+ coercions : & VecGraph < ty:: TyVid , true > ,
454
473
) {
455
474
let DivergingFallbackBehavior :: ToUnit = behavior else { return } ;
456
475
@@ -478,20 +497,22 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
478
497
} ;
479
498
480
499
// If we have no errors with `fallback = ()`, but *do* have errors with `fallback = !`,
481
- // then this code will be broken by the never type fallback change.qba
500
+ // then this code will be broken by the never type fallback change.
482
501
let unit_errors = remaining_errors_if_fallback_to ( self . tcx . types . unit ) ;
483
502
if unit_errors. is_empty ( )
484
503
&& let mut never_errors = remaining_errors_if_fallback_to ( self . tcx . types . never )
485
504
&& let [ ref mut never_error, ..] = never_errors. as_mut_slice ( )
486
505
{
487
506
self . adjust_fulfillment_error_for_expr_obligation ( never_error) ;
507
+ let sugg = self . try_to_suggest_annotations ( diverging_vids, coercions) ;
488
508
self . tcx . emit_node_span_lint (
489
509
lint:: builtin:: DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK ,
490
510
self . tcx . local_def_id_to_hir_id ( self . body_id ) ,
491
511
self . tcx . def_span ( self . body_id ) ,
492
512
errors:: DependencyOnUnitNeverTypeFallback {
493
513
obligation_span : never_error. obligation . cause . span ,
494
514
obligation : never_error. obligation . predicate ,
515
+ sugg,
495
516
} ,
496
517
)
497
518
}
@@ -541,6 +562,47 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
541
562
fn root_vid ( & self , ty : Ty < ' tcx > ) -> Option < ty:: TyVid > {
542
563
Some ( self . root_var ( self . shallow_resolve ( ty) . ty_vid ( ) ?) )
543
564
}
565
+
566
+ fn try_to_suggest_annotations (
567
+ & self ,
568
+ diverging_vids : & [ ty:: TyVid ] ,
569
+ coercions : & VecGraph < ty:: TyVid , true > ,
570
+ ) -> errors:: SuggestAnnotations {
571
+ let body =
572
+ self . tcx . hir ( ) . maybe_body_owned_by ( self . body_id ) . expect ( "body id must have an owner" ) ;
573
+ // For each diverging var, look through the HIR for a place to give it
574
+ // a type annotation. We do this per var because we only really need one
575
+ // per var.
576
+ let suggestion_spans = diverging_vids
577
+ . iter ( )
578
+ . copied ( )
579
+ . filter_map ( |vid| {
580
+ let reachable_vids =
581
+ graph:: depth_first_search_as_undirected ( coercions, vid) . collect ( ) ;
582
+ VidVisitor { reachable_vids, fcx : self } . visit_expr ( body. value ) . break_value ( )
583
+ } )
584
+ . collect ( ) ;
585
+ errors:: SuggestAnnotations { suggestion_spans }
586
+ }
587
+ }
588
+
589
+ struct VidVisitor < ' a , ' tcx > {
590
+ reachable_vids : FxHashSet < ty:: TyVid > ,
591
+ fcx : & ' a FnCtxt < ' a , ' tcx > ,
592
+ }
593
+ impl < ' tcx > Visitor < ' tcx > for VidVisitor < ' _ , ' tcx > {
594
+ type Result = ControlFlow < Span > ;
595
+
596
+ fn visit_ty ( & mut self , hir_ty : & ' tcx hir:: Ty < ' tcx > ) -> Self :: Result {
597
+ if let hir:: TyKind :: Infer = hir_ty. kind
598
+ && let ty = self . fcx . typeck_results . borrow ( ) . node_type ( hir_ty. hir_id )
599
+ && let Some ( vid) = self . fcx . root_vid ( ty)
600
+ && self . reachable_vids . contains ( & vid)
601
+ {
602
+ return ControlFlow :: Break ( hir_ty. span ) ;
603
+ }
604
+ hir:: intravisit:: walk_ty ( self , hir_ty)
605
+ }
544
606
}
545
607
546
608
#[ derive( Debug , Copy , Clone ) ]
0 commit comments