@@ -34,6 +34,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
34
34
pub fn resolve_type_vars_in_body (
35
35
& self ,
36
36
body : & ' tcx hir:: Body < ' tcx > ,
37
+ from_diverging_fallback : & Vec < Ty < ' tcx > > ,
37
38
) -> & ' tcx ty:: TypeckResults < ' tcx > {
38
39
let item_id = self . tcx . hir ( ) . body_owner ( body. id ( ) ) ;
39
40
let item_def_id = self . tcx . hir ( ) . local_def_id ( item_id) ;
@@ -43,7 +44,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
43
44
let rustc_dump_user_substs =
44
45
self . tcx . has_attr ( item_def_id. to_def_id ( ) , sym:: rustc_dump_user_substs) ;
45
46
46
- let mut wbcx = WritebackCx :: new ( self , body, rustc_dump_user_substs) ;
47
+ let mut wbcx =
48
+ WritebackCx :: new ( self , body, rustc_dump_user_substs, from_diverging_fallback) ;
47
49
for param in body. params {
48
50
wbcx. visit_node_id ( param. pat . span , param. hir_id ) ;
49
51
}
@@ -100,13 +102,19 @@ struct WritebackCx<'cx, 'tcx> {
100
102
body : & ' tcx hir:: Body < ' tcx > ,
101
103
102
104
rustc_dump_user_substs : bool ,
105
+
106
+ /// List of type variables which became the never type `!`
107
+ /// as a result of fallback.
108
+ /// This is used to issue lints and warnings for the user.
109
+ from_diverging_fallback : & ' cx Vec < Ty < ' tcx > > ,
103
110
}
104
111
105
112
impl < ' cx , ' tcx > WritebackCx < ' cx , ' tcx > {
106
113
fn new (
107
114
fcx : & ' cx FnCtxt < ' cx , ' tcx > ,
108
115
body : & ' tcx hir:: Body < ' tcx > ,
109
116
rustc_dump_user_substs : bool ,
117
+ from_diverging_fallback : & ' cx Vec < Ty < ' tcx > > ,
110
118
) -> WritebackCx < ' cx , ' tcx > {
111
119
let owner = body. id ( ) . hir_id . owner ;
112
120
@@ -115,6 +123,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
115
123
typeck_results : ty:: TypeckResults :: new ( owner) ,
116
124
body,
117
125
rustc_dump_user_substs,
126
+ from_diverging_fallback,
118
127
}
119
128
}
120
129
@@ -521,8 +530,35 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
521
530
self . visit_adjustments ( span, hir_id) ;
522
531
523
532
// Resolve the type of the node with id `node_id`
524
- let n_ty = self . fcx . node_ty ( hir_id) ;
525
- let n_ty = self . resolve ( & n_ty, & span) ;
533
+ let n_ty_original = self . fcx . node_ty ( hir_id) ;
534
+ let n_ty = self . resolve ( & n_ty_original, & span) ;
535
+
536
+ debug ! ( "visit_node_id: {:?}" , self . from_diverging_fallback) ;
537
+ // check whether the node type contains any of the variables that
538
+ // became `!` as a result of type fallback but they are not part of the
539
+ // dead nodes. if so, warn. Note that, we concern ourselves with only
540
+ // the `n_ty_original` and don't `walk()` the subparts of a type. So, for a
541
+ // variable like `Foo<Bar<Bas<...<N>>>>` even if `N` is diverging type,
542
+ // we will not generate a warning. This might be okay as sometimes we may
543
+ // have things like `Result<i32, T> where even though `T` is diverging,
544
+ // it might never be used and warning would be confusing for the user.
545
+ if !self . from_diverging_fallback . is_empty ( ) {
546
+ debug ! ( "hir_id:{}" , & hir_id) ;
547
+ debug ! ( "n_ty_original:{}" , & n_ty_original) ;
548
+ if !self . fcx . dead_nodes . borrow ( ) . contains ( & hir_id)
549
+ && self . from_diverging_fallback . contains ( & n_ty_original)
550
+ {
551
+ self . tcx ( ) . struct_span_lint_hir (
552
+ rustc_session:: lint:: builtin:: FALL_BACK_TO_NEVER_TYPE ,
553
+ hir_id,
554
+ span,
555
+ |lint| {
556
+ lint. build ( & format ! ( "resulted from diverging fallback: {:?}" , n_ty) ) . emit ( )
557
+ } ,
558
+ ) ;
559
+ }
560
+ }
561
+
526
562
self . write_ty_to_typeck_results ( hir_id, n_ty) ;
527
563
debug ! ( "node {:?} has type {:?}" , hir_id, n_ty) ;
528
564
0 commit comments