@@ -627,6 +627,7 @@ struct InferredPath<'tcx> {
627
627
span : Span ,
628
628
ty : Option < Ty < ' tcx > > ,
629
629
args : Option < Cow < ' tcx , [ Ty < ' tcx > ] > > ,
630
+ unresolved_vars : Vec < Vec < Ty < ' tcx > > > ,
630
631
}
631
632
632
633
impl < ' a , ' tcx > Deref for FnCtxt < ' a , ' tcx > {
@@ -1069,28 +1070,72 @@ fn typeck_tables_of_with_fallback<'tcx>(
1069
1070
. borrow ( )
1070
1071
. iter ( )
1071
1072
. map ( |( id, path) | ( * id, path. clone ( ) ) )
1072
- . filter ( |( hir_id, path) | {
1073
+ . filter_map ( |( hir_id, mut path) | {
1073
1074
debug ! (
1074
1075
"typeck_tables_of_with_fallback: inspecting path ({:?}, {:?})" ,
1075
1076
hir_id, path
1076
1077
) ;
1077
- let debug_resolved = fcx. infcx . resolve_vars_if_possible ( & path. ty ) ;
1078
- if fcx. infcx . unresolved_type_vars ( & path. ty ) . is_some ( ) {
1078
+
1079
+ let ty_resolved = fcx. infcx . resolve_vars_if_possible ( & path. ty ) ;
1080
+
1081
+ let fn_substs = match ty_resolved {
1082
+ Some ( ty:: TyS { kind : ty:: FnDef ( _, substs) , .. } ) => substs,
1083
+ _ => {
1084
+ debug ! (
1085
+ "typeck_tables_of_with_fallback: non-fn ty {:?}, skipping" ,
1086
+ ty_resolved
1087
+ ) ;
1088
+ return None ;
1089
+ }
1090
+ } ;
1091
+
1092
+ if fcx. infcx . unresolved_type_vars ( fn_substs) . is_some ( ) {
1093
+ struct TyVarFinder < ' a , ' tcx > {
1094
+ infcx : & ' a InferCtxt < ' a , ' tcx > ,
1095
+ vars : Vec < Ty < ' tcx > > ,
1096
+ }
1097
+ impl < ' a , ' tcx > TypeFolder < ' tcx > for TyVarFinder < ' a , ' tcx > {
1098
+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
1099
+ self . infcx . tcx
1100
+ }
1101
+
1102
+ fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
1103
+ if let ty:: Infer ( ty:: InferTy :: TyVar ( _) ) = t. kind {
1104
+ self . vars . push ( t) ;
1105
+ }
1106
+ t. super_fold_with ( self )
1107
+ }
1108
+ }
1109
+
1110
+ for subst in fn_substs. types ( ) {
1111
+ let mut finder = TyVarFinder { infcx : & fcx. infcx , vars : vec ! [ ] } ;
1112
+ path. ty . fold_with ( & mut finder) ;
1113
+ path. unresolved_vars . push ( finder. vars ) ;
1114
+ }
1115
+
1079
1116
debug ! (
1080
- "typeck_tables_of_with_fallback: unresolved vars in ty: {:?}" ,
1081
- debug_resolved
1117
+ "typeck_tables_of_with_fallback: unresolved vars in ty {:?} : {:?}" ,
1118
+ ty_resolved , path . unresolved_vars
1082
1119
) ;
1083
- true
1120
+
1121
+ Some ( ( hir_id, path) )
1084
1122
} else {
1085
1123
debug ! (
1086
1124
"typeck_tables_of_with_fallback: all vars resolved in ty: {:?}" ,
1087
- debug_resolved
1125
+ ty_resolved
1088
1126
) ;
1089
- false
1127
+ None
1090
1128
}
1091
1129
} )
1092
1130
. collect ( ) ;
1093
1131
1132
+ let unconstrained_diverging: Vec < _ > = fcx
1133
+ . unsolved_variables ( )
1134
+ . iter ( )
1135
+ . cloned ( )
1136
+ . filter ( |ty| fcx. infcx . type_var_diverges ( ty) )
1137
+ . collect ( ) ;
1138
+
1094
1139
// We do fallback in two passes, to try to generate
1095
1140
// better error messages.
1096
1141
// The first time, we do *not* replace opaque types.
@@ -1150,7 +1195,7 @@ fn typeck_tables_of_with_fallback<'tcx>(
1150
1195
if let ty:: FnDef ( _, substs) = ty. kind {
1151
1196
debug ! ( "Got substs: {:?}" , substs) ;
1152
1197
let mut args_inhabited = true ;
1153
- let mut substs_inhabited = true ;
1198
+ let mut uninhabited_subst = None ;
1154
1199
1155
1200
for arg in & * path. args . unwrap ( ) {
1156
1201
let resolved_arg = fcx. infcx . resolve_vars_if_possible ( arg) ;
@@ -1164,25 +1209,82 @@ fn typeck_tables_of_with_fallback<'tcx>(
1164
1209
}
1165
1210
}
1166
1211
1167
- for subst_ty in substs. types ( ) {
1212
+ for ( subst_ty, vars ) in substs. types ( ) . zip ( path . unresolved_vars . into_iter ( ) ) {
1168
1213
let resolved_subst = fcx. infcx . resolve_vars_if_possible ( & subst_ty) ;
1169
1214
if resolved_subst. conservative_is_privately_uninhabited ( tcx) {
1170
1215
debug ! ( "Subst is uninhabited: {:?}" , resolved_subst) ;
1171
- substs_inhabited = false ;
1172
- break ;
1216
+ if !vars. is_empty ( ) {
1217
+ debug ! ( "Found fallback vars: {:?}" , vars) ;
1218
+ uninhabited_subst = Some ( ( resolved_subst, vars) ) ;
1219
+ break ;
1220
+ } else {
1221
+ debug ! ( "No fallback vars" )
1222
+ }
1173
1223
} else {
1174
1224
debug ! ( "Subst is inhabited: {:?}" , resolved_subst) ;
1175
1225
}
1176
1226
}
1177
1227
1178
- if args_inhabited && !substs_inhabited {
1228
+ if let ( true , Some ( ( subst , vars ) ) ) = ( args_inhabited , uninhabited_subst ) {
1179
1229
debug ! ( "All arguments are inhabited, at least one subst is not inhabited!" ) ;
1230
+
1231
+ let mut best_diverging_var = None ;
1232
+ let mut best_var = None ;
1233
+
1234
+ for var in vars {
1235
+ for diverging_var in & unconstrained_diverging {
1236
+ match ( & var. kind , & diverging_var. kind ) {
1237
+ (
1238
+ ty:: Infer ( ty:: InferTy :: TyVar ( vid1) ) ,
1239
+ ty:: Infer ( ty:: InferTy :: TyVar ( vid2) ) ,
1240
+ ) => {
1241
+ if fcx
1242
+ . infcx
1243
+ . type_variables
1244
+ . borrow_mut ( )
1245
+ . sub_unified ( * vid1, * vid2)
1246
+ {
1247
+ debug ! (
1248
+ "Type variable {:?} is equal to diverging var {:?}" ,
1249
+ var, diverging_var
1250
+ ) ;
1251
+ best_var = Some ( var) ;
1252
+ best_diverging_var = Some ( diverging_var) ;
1253
+ }
1254
+ }
1255
+ _ => bug ! (
1256
+ "Unexpected types: var={:?} diverging_var={:?}" ,
1257
+ var,
1258
+ diverging_var
1259
+ ) ,
1260
+ }
1261
+ }
1262
+ }
1263
+
1264
+ let ( var_span, diverging_var_span) =
1265
+ match ( & best_var. unwrap ( ) . kind , & best_diverging_var. unwrap ( ) . kind ) {
1266
+ (
1267
+ ty:: Infer ( ty:: InferTy :: TyVar ( var_vid) ) ,
1268
+ ty:: Infer ( ty:: InferTy :: TyVar ( diverging_var_vid) ) ,
1269
+ ) => (
1270
+ fcx. infcx . type_variables . borrow ( ) . var_origin ( * var_vid) . span ,
1271
+ fcx. infcx
1272
+ . type_variables
1273
+ . borrow ( )
1274
+ . var_origin ( * diverging_var_vid)
1275
+ . span ,
1276
+ ) ,
1277
+ _ => bug ! ( "Type is not a ty variable: {:?}" , best_var) ,
1278
+ } ;
1279
+
1180
1280
fcx. tcx ( )
1181
1281
. sess
1182
1282
. struct_span_warn (
1183
1283
path. span ,
1184
1284
"Fallback to `!` may introduce undefined behavior" ,
1185
1285
)
1286
+ . span_note ( var_span, "the type here was inferred to `!`" )
1287
+ . span_note ( diverging_var_span, "... due to this expression" )
1186
1288
. emit ( ) ;
1187
1289
}
1188
1290
}
@@ -3837,7 +3939,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3837
3939
match self . inferred_paths . borrow_mut ( ) . entry ( expr. hir_id ) {
3838
3940
Entry :: Vacant ( e) => {
3839
3941
debug ! ( "check_argument_types: making new entry for types {:?}" , fn_inputs) ;
3840
- e. insert ( InferredPath { span : sp, ty : None , args : Some ( fn_inputs. clone ( ) ) } ) ;
3942
+ e. insert ( InferredPath {
3943
+ span : sp,
3944
+ ty : None ,
3945
+ args : Some ( fn_inputs. clone ( ) ) ,
3946
+ unresolved_vars : vec ! [ ] ,
3947
+ } ) ;
3841
3948
}
3842
3949
Entry :: Occupied ( mut e) => {
3843
3950
debug ! (
@@ -5552,6 +5659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5552
5659
span : * p_span,
5553
5660
ty : Some ( ty_substituted) ,
5554
5661
args : None ,
5662
+ unresolved_vars : vec ! [ ] ,
5555
5663
} ) ;
5556
5664
}
5557
5665
Entry :: Occupied ( mut e) => {
0 commit comments