Skip to content

Commit 29aee6a

Browse files
Restore suggestion based off of backwards inference from bad usage to method call
1 parent e72c45a commit 29aee6a

File tree

3 files changed

+88
-59
lines changed

3 files changed

+88
-59
lines changed

compiler/rustc_hir_typeck/src/demand.rs

Lines changed: 83 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -259,49 +259,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
259259
hir.body(hir.maybe_body_owned_by(self.body_id).expect("expected item to have body"));
260260
expr_finder.visit_expr(body.value);
261261

262-
let fudge_ty = |ty: Ty<'tcx>| {
263-
use rustc_infer::infer::type_variable::*;
264-
use rustc_middle::infer::unify_key::*;
265-
ty.fold_with(&mut BottomUpFolder {
266-
tcx: self.tcx,
267-
ty_op: |ty| {
268-
if let ty::Infer(infer) = ty.kind() {
269-
match infer {
270-
ty::InferTy::TyVar(_) => self.next_ty_var(TypeVariableOrigin {
271-
kind: TypeVariableOriginKind::MiscVariable,
272-
span: DUMMY_SP,
273-
}),
274-
ty::InferTy::IntVar(_) => self.next_int_var(),
275-
ty::InferTy::FloatVar(_) => self.next_float_var(),
276-
_ => bug!(),
277-
}
278-
} else {
279-
ty
280-
}
281-
},
282-
lt_op: |_| self.tcx.lifetimes.re_erased,
283-
ct_op: |ct| {
284-
if let ty::ConstKind::Infer(_) = ct.kind() {
285-
self.next_const_var(
286-
ct.ty(),
287-
ConstVariableOrigin {
288-
kind: ConstVariableOriginKind::MiscVariable,
289-
span: DUMMY_SP,
290-
},
291-
)
292-
} else {
293-
ct
262+
use rustc_infer::infer::type_variable::*;
263+
use rustc_middle::infer::unify_key::*;
264+
265+
let mut fudger = BottomUpFolder {
266+
tcx: self.tcx,
267+
ty_op: |ty| {
268+
if let ty::Infer(infer) = ty.kind() {
269+
match infer {
270+
ty::InferTy::TyVar(_) => self.next_ty_var(TypeVariableOrigin {
271+
kind: TypeVariableOriginKind::MiscVariable,
272+
span: DUMMY_SP,
273+
}),
274+
ty::InferTy::IntVar(_) => self.next_int_var(),
275+
ty::InferTy::FloatVar(_) => self.next_float_var(),
276+
_ => bug!(),
294277
}
295-
},
296-
})
297-
};
298-
299-
let fudge_equals_found_ty = |use_ty: Ty<'tcx>| {
300-
let use_ty = fudge_ty(use_ty);
301-
self.can_eq(self.param_env, expected_ty, use_ty)
278+
} else {
279+
ty
280+
}
281+
},
282+
lt_op: |_| self.tcx.lifetimes.re_erased,
283+
ct_op: |ct| {
284+
if let ty::ConstKind::Infer(_) = ct.kind() {
285+
self.next_const_var(
286+
ct.ty(),
287+
ConstVariableOrigin {
288+
kind: ConstVariableOriginKind::MiscVariable,
289+
span: DUMMY_SP,
290+
},
291+
)
292+
} else {
293+
ct
294+
}
295+
},
302296
};
303297

304-
if !fudge_equals_found_ty(init_ty) {
298+
if !self.can_eq(self.param_env, expected_ty, init_ty.fold_with(&mut fudger)) {
305299
return false;
306300
}
307301

@@ -317,7 +311,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
317311

318312
// If the type is not constrained in a way making it not possible to
319313
// equate with `expected_ty` by this point, skip.
320-
if fudge_equals_found_ty(next_use_ty) {
314+
if self.can_eq(self.param_env, expected_ty, next_use_ty.fold_with(&mut fudger)) {
321315
continue;
322316
}
323317

@@ -326,26 +320,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
326320
&& rcvr.hir_id == binding.hir_id
327321
{
328322
let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; };
329-
let rcvr_ty = fudge_ty(rcvr_ty);
330-
if let Ok(method) =
323+
let rcvr_ty = rcvr_ty.fold_with(&mut fudger);
324+
let Ok(method) =
331325
self.lookup_method(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args)
326+
else {
327+
continue;
328+
};
329+
330+
// NOTE: For future removers of `fudge_inference_if_ok`, you
331+
// can replace this with another call to `lookup_method` but
332+
// using `expected_ty` as the rcvr.
333+
let ideal_method_sig: Result<_, TypeError<'tcx>> = self.fudge_inference_if_ok(|| {
334+
let _ = self.at(&ObligationCause::dummy(), self.param_env).eq(rcvr_ty, expected_ty)?;
335+
Ok(method.sig)
336+
});
337+
338+
for (idx, (expected_arg_ty, arg_expr)) in
339+
std::iter::zip(&method.sig.inputs()[1..], args).enumerate()
332340
{
333-
for (expected_arg_ty, arg_expr) in std::iter::zip(&method.sig.inputs()[1..], args) {
334-
let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; };
335-
let arg_ty = fudge_ty(arg_ty);
336-
let _ = self.try_coerce(arg_expr, arg_ty, *expected_arg_ty, AllowTwoPhase::No, None);
337-
if !self.can_eq(self.param_env, rcvr_ty, expected_ty) {
338-
err.span_label(
339-
arg_expr.span,
340-
format!("this argument has type `{arg_ty}`...")
341-
);
342-
err.span_label(
343-
binding.span,
344-
format!("... which constrains `{ident}` to have type `{next_use_ty}`")
345-
);
346-
return true;
347-
}
341+
let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; };
342+
let arg_ty = arg_ty.fold_with(&mut fudger);
343+
let _ = self.try_coerce(
344+
arg_expr,
345+
arg_ty,
346+
*expected_arg_ty,
347+
AllowTwoPhase::No,
348+
None,
349+
);
350+
if self.can_eq(self.param_env, rcvr_ty, expected_ty) {
351+
continue;
352+
}
353+
err.span_label(
354+
arg_expr.span,
355+
format!("this argument has type `{arg_ty}`..."),
356+
);
357+
err.span_label(
358+
binding.span,
359+
format!(
360+
"... which constrains `{ident}` to have type `{next_use_ty}`"
361+
),
362+
);
363+
if let Ok(ideal_method_sig) = ideal_method_sig {
364+
self.emit_type_mismatch_suggestions(
365+
err,
366+
arg_expr,
367+
arg_ty,
368+
ideal_method_sig.inputs()[idx + 1],
369+
None,
370+
None,
371+
);
348372
}
373+
return true;
349374
}
350375
}
351376

tests/ui/type/type-check/point-at-inference.fixed

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ fn main() {
66
let mut foo = vec![];
77
baz(&foo);
88
for i in &v {
9-
foo.push(i);
9+
foo.push(*i);
1010
}
1111
baz(&foo);
1212
bar(foo); //~ ERROR E0308

tests/ui/type/type-check/point-at-inference.stderr

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ note: function defined here
1818
|
1919
LL | fn bar(_: Vec<i32>) {}
2020
| ^^^ -----------
21+
help: consider dereferencing the borrow
22+
|
23+
LL | foo.push(*i);
24+
| +
2125

2226
error: aborting due to previous error
2327

0 commit comments

Comments
 (0)