@@ -8,12 +8,17 @@ use rustc_data_structures::{
88use rustc_hir as hir;
99use rustc_hir:: intravisit:: Visitor ;
1010use rustc_hir:: HirId ;
11- use rustc_infer:: infer:: { DefineOpaqueTypes , InferOk } ;
1211use rustc_middle:: bug;
12+ use rustc_infer:: {
13+ infer:: { DefineOpaqueTypes , InferOk } ,
14+ traits:: ObligationCause ,
15+ } ;
1316use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable } ;
1417use rustc_session:: lint;
1518use rustc_span:: DUMMY_SP ;
1619use rustc_span:: { def_id:: LocalDefId , Span } ;
20+ use rustc_trait_selection:: traits:: ObligationCtxt ;
21+ use rustc_type_ir:: TyVid ;
1722
1823#[ derive( Copy , Clone ) ]
1924pub enum DivergingFallbackBehavior {
@@ -344,6 +349,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
344349 // `!`.
345350 let mut diverging_fallback = UnordMap :: with_capacity ( diverging_vids. len ( ) ) ;
346351 let unsafe_infer_vars = OnceCell :: new ( ) ;
352+
353+ self . lint_obligations_broken_by_never_type_fallback_change ( behavior, & diverging_vids) ;
354+
347355 for & diverging_vid in & diverging_vids {
348356 let diverging_ty = Ty :: new_var ( self . tcx , diverging_vid) ;
349357 let root_vid = self . root_var ( diverging_vid) ;
@@ -363,7 +371,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
363371 output : infer_var_infos. items ( ) . any ( |info| info. output ) ,
364372 } ;
365373
366- let mut fallback_to = |ty| {
374+ let mut fallback_to = |ty : Ty < ' tcx > | {
367375 let unsafe_infer_vars = unsafe_infer_vars. get_or_init ( || {
368376 let unsafe_infer_vars = compute_unsafe_infer_vars ( self . root_ctxt , self . body_id ) ;
369377 debug ! ( ?unsafe_infer_vars) ;
@@ -464,6 +472,46 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
464472 diverging_fallback
465473 }
466474
475+ fn lint_obligations_broken_by_never_type_fallback_change (
476+ & self ,
477+ behavior : DivergingFallbackBehavior ,
478+ diverging_vids : & [ TyVid ] ,
479+ ) {
480+ let DivergingFallbackBehavior :: FallbackToUnit = behavior else { return } ;
481+
482+ // Returns errors which happen if fallback is set to `fallback`
483+ let try_out = |fallback| {
484+ self . probe ( |_| {
485+ let obligations = self . fulfillment_cx . borrow ( ) . pending_obligations ( ) ;
486+ let ocx = ObligationCtxt :: new ( & self . infcx ) ;
487+ ocx. register_obligations ( obligations. iter ( ) . cloned ( ) ) ;
488+
489+ for & diverging_vid in diverging_vids {
490+ let diverging_ty = Ty :: new_var ( self . tcx , diverging_vid) ;
491+
492+ _ = ocx. eq ( & ObligationCause :: dummy ( ) , self . param_env , diverging_ty, fallback) ;
493+ }
494+
495+ ocx. select_where_possible ( )
496+ } )
497+ } ;
498+
499+ // If we have no errors with `fallback = ()`, but *do* have errors with `fallback = !`,
500+ // then this code will be broken by the never type fallback change.qba
501+ let unit_errors = try_out ( self . tcx . types . unit ) ;
502+ if unit_errors. is_empty ( )
503+ && let never_errors = try_out ( self . tcx . types . never )
504+ && !never_errors. is_empty ( )
505+ {
506+ self . tcx . emit_node_span_lint (
507+ lint:: builtin:: DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK ,
508+ self . tcx . local_def_id_to_hir_id ( self . body_id ) ,
509+ self . tcx . def_span ( self . body_id ) ,
510+ errors:: DependencyOnUnitNeverTypeFallback { } ,
511+ )
512+ }
513+ }
514+
467515 /// Returns a graph whose nodes are (unresolved) inference variables and where
468516 /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`.
469517 fn create_coercion_graph ( & self ) -> VecGraph < ty:: TyVid , true > {
0 commit comments