11use std:: cell:: OnceCell ;
2+ use std:: ops:: ControlFlow ;
23
4+ use rustc_data_structures:: fx:: FxHashSet ;
35use rustc_data_structures:: graph:: iterate:: DepthFirstSearch ;
46use rustc_data_structures:: graph:: vec_graph:: VecGraph ;
57use rustc_data_structures:: graph:: { self } ;
@@ -321,7 +323,11 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
321323 let mut diverging_fallback = UnordMap :: with_capacity ( diverging_vids. len ( ) ) ;
322324 let unsafe_infer_vars = OnceCell :: new ( ) ;
323325
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+ ) ;
325331
326332 for & diverging_vid in & diverging_vids {
327333 let diverging_ty = Ty :: new_var ( self . tcx , diverging_vid) ;
@@ -429,19 +435,31 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
429435 . filter_map ( |x| unsafe_infer_vars. get ( & x) . copied ( ) )
430436 . collect :: < Vec < _ > > ( ) ;
431437
438+ let sugg = self . try_to_suggest_annotations ( & [ root_vid] , coercion_graph) ;
439+
432440 for ( hir_id, span, reason) in affected_unsafe_infer_vars {
433441 self . tcx . emit_node_span_lint (
434442 lint:: builtin:: NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE ,
435443 hir_id,
436444 span,
437445 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+ }
441455 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 ( ) }
443462 }
444- UnsafeUseReason :: Deref => errors:: NeverTypeFallbackFlowingIntoUnsafe :: Deref ,
445463 } ,
446464 ) ;
447465 }
@@ -451,6 +469,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
451469 & self ,
452470 behavior : DivergingFallbackBehavior ,
453471 diverging_vids : & [ ty:: TyVid ] ,
472+ coercions : & VecGraph < ty:: TyVid , true > ,
454473 ) {
455474 let DivergingFallbackBehavior :: ToUnit = behavior else { return } ;
456475
@@ -478,20 +497,22 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
478497 } ;
479498
480499 // 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.
482501 let unit_errors = remaining_errors_if_fallback_to ( self . tcx . types . unit ) ;
483502 if unit_errors. is_empty ( )
484503 && let mut never_errors = remaining_errors_if_fallback_to ( self . tcx . types . never )
485504 && let [ ref mut never_error, ..] = never_errors. as_mut_slice ( )
486505 {
487506 self . adjust_fulfillment_error_for_expr_obligation ( never_error) ;
507+ let sugg = self . try_to_suggest_annotations ( diverging_vids, coercions) ;
488508 self . tcx . emit_node_span_lint (
489509 lint:: builtin:: DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK ,
490510 self . tcx . local_def_id_to_hir_id ( self . body_id ) ,
491511 self . tcx . def_span ( self . body_id ) ,
492512 errors:: DependencyOnUnitNeverTypeFallback {
493513 obligation_span : never_error. obligation . cause . span ,
494514 obligation : never_error. obligation . predicate ,
515+ sugg,
495516 } ,
496517 )
497518 }
@@ -541,6 +562,47 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
541562 fn root_vid ( & self , ty : Ty < ' tcx > ) -> Option < ty:: TyVid > {
542563 Some ( self . root_var ( self . shallow_resolve ( ty) . ty_vid ( ) ?) )
543564 }
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+ }
544606}
545607
546608#[ derive( Debug , Copy , Clone ) ]
0 commit comments