Skip to content

Commit d0dc1e3

Browse files
committed
Make the error message much better
1 parent 3a22be9 commit d0dc1e3

File tree

1 file changed

+122
-14
lines changed
  • src/librustc_typeck/check

1 file changed

+122
-14
lines changed

src/librustc_typeck/check/mod.rs

Lines changed: 122 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,7 @@ struct InferredPath<'tcx> {
627627
span: Span,
628628
ty: Option<Ty<'tcx>>,
629629
args: Option<Cow<'tcx, [Ty<'tcx>]>>,
630+
unresolved_vars: Vec<Vec<Ty<'tcx>>>,
630631
}
631632

632633
impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
@@ -1069,28 +1070,72 @@ fn typeck_tables_of_with_fallback<'tcx>(
10691070
.borrow()
10701071
.iter()
10711072
.map(|(id, path)| (*id, path.clone()))
1072-
.filter(|(hir_id, path)| {
1073+
.filter_map(|(hir_id, mut path)| {
10731074
debug!(
10741075
"typeck_tables_of_with_fallback: inspecting path ({:?}, {:?})",
10751076
hir_id, path
10761077
);
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+
10791116
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
10821119
);
1083-
true
1120+
1121+
Some((hir_id, path))
10841122
} else {
10851123
debug!(
10861124
"typeck_tables_of_with_fallback: all vars resolved in ty: {:?}",
1087-
debug_resolved
1125+
ty_resolved
10881126
);
1089-
false
1127+
None
10901128
}
10911129
})
10921130
.collect();
10931131

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+
10941139
// We do fallback in two passes, to try to generate
10951140
// better error messages.
10961141
// The first time, we do *not* replace opaque types.
@@ -1150,7 +1195,7 @@ fn typeck_tables_of_with_fallback<'tcx>(
11501195
if let ty::FnDef(_, substs) = ty.kind {
11511196
debug!("Got substs: {:?}", substs);
11521197
let mut args_inhabited = true;
1153-
let mut substs_inhabited = true;
1198+
let mut uninhabited_subst = None;
11541199

11551200
for arg in &*path.args.unwrap() {
11561201
let resolved_arg = fcx.infcx.resolve_vars_if_possible(arg);
@@ -1164,25 +1209,82 @@ fn typeck_tables_of_with_fallback<'tcx>(
11641209
}
11651210
}
11661211

1167-
for subst_ty in substs.types() {
1212+
for (subst_ty, vars) in substs.types().zip(path.unresolved_vars.into_iter()) {
11681213
let resolved_subst = fcx.infcx.resolve_vars_if_possible(&subst_ty);
11691214
if resolved_subst.conservative_is_privately_uninhabited(tcx) {
11701215
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+
}
11731223
} else {
11741224
debug!("Subst is inhabited: {:?}", resolved_subst);
11751225
}
11761226
}
11771227

1178-
if args_inhabited && !substs_inhabited {
1228+
if let (true, Some((subst, vars))) = (args_inhabited, uninhabited_subst) {
11791229
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+
11801280
fcx.tcx()
11811281
.sess
11821282
.struct_span_warn(
11831283
path.span,
11841284
"Fallback to `!` may introduce undefined behavior",
11851285
)
1286+
.span_note(var_span, "the type here was inferred to `!`")
1287+
.span_note(diverging_var_span, "... due to this expression")
11861288
.emit();
11871289
}
11881290
}
@@ -3837,7 +3939,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
38373939
match self.inferred_paths.borrow_mut().entry(expr.hir_id) {
38383940
Entry::Vacant(e) => {
38393941
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+
});
38413948
}
38423949
Entry::Occupied(mut e) => {
38433950
debug!(
@@ -5552,6 +5659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
55525659
span: *p_span,
55535660
ty: Some(ty_substituted),
55545661
args: None,
5662+
unresolved_vars: vec![],
55555663
});
55565664
}
55575665
Entry::Occupied(mut e) => {

0 commit comments

Comments
 (0)