Restore suggestion based off of backwards inference from bad usage to method call
This commit is contained in:
parent
e72c45ad98
commit
29aee6a125
3 changed files with 88 additions and 59 deletions
|
@ -259,49 +259,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
hir.body(hir.maybe_body_owned_by(self.body_id).expect("expected item to have body"));
|
hir.body(hir.maybe_body_owned_by(self.body_id).expect("expected item to have body"));
|
||||||
expr_finder.visit_expr(body.value);
|
expr_finder.visit_expr(body.value);
|
||||||
|
|
||||||
let fudge_ty = |ty: Ty<'tcx>| {
|
use rustc_infer::infer::type_variable::*;
|
||||||
use rustc_infer::infer::type_variable::*;
|
use rustc_middle::infer::unify_key::*;
|
||||||
use rustc_middle::infer::unify_key::*;
|
|
||||||
ty.fold_with(&mut BottomUpFolder {
|
let mut fudger = BottomUpFolder {
|
||||||
tcx: self.tcx,
|
tcx: self.tcx,
|
||||||
ty_op: |ty| {
|
ty_op: |ty| {
|
||||||
if let ty::Infer(infer) = ty.kind() {
|
if let ty::Infer(infer) = ty.kind() {
|
||||||
match infer {
|
match infer {
|
||||||
ty::InferTy::TyVar(_) => self.next_ty_var(TypeVariableOrigin {
|
ty::InferTy::TyVar(_) => self.next_ty_var(TypeVariableOrigin {
|
||||||
kind: TypeVariableOriginKind::MiscVariable,
|
kind: TypeVariableOriginKind::MiscVariable,
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
}),
|
}),
|
||||||
ty::InferTy::IntVar(_) => self.next_int_var(),
|
ty::InferTy::IntVar(_) => self.next_int_var(),
|
||||||
ty::InferTy::FloatVar(_) => self.next_float_var(),
|
ty::InferTy::FloatVar(_) => self.next_float_var(),
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ty
|
|
||||||
}
|
}
|
||||||
},
|
} else {
|
||||||
lt_op: |_| self.tcx.lifetimes.re_erased,
|
ty
|
||||||
ct_op: |ct| {
|
}
|
||||||
if let ty::ConstKind::Infer(_) = ct.kind() {
|
},
|
||||||
self.next_const_var(
|
lt_op: |_| self.tcx.lifetimes.re_erased,
|
||||||
ct.ty(),
|
ct_op: |ct| {
|
||||||
ConstVariableOrigin {
|
if let ty::ConstKind::Infer(_) = ct.kind() {
|
||||||
kind: ConstVariableOriginKind::MiscVariable,
|
self.next_const_var(
|
||||||
span: DUMMY_SP,
|
ct.ty(),
|
||||||
},
|
ConstVariableOrigin {
|
||||||
)
|
kind: ConstVariableOriginKind::MiscVariable,
|
||||||
} else {
|
span: DUMMY_SP,
|
||||||
ct
|
},
|
||||||
}
|
)
|
||||||
},
|
} else {
|
||||||
})
|
ct
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let fudge_equals_found_ty = |use_ty: Ty<'tcx>| {
|
if !self.can_eq(self.param_env, expected_ty, init_ty.fold_with(&mut fudger)) {
|
||||||
let use_ty = fudge_ty(use_ty);
|
|
||||||
self.can_eq(self.param_env, expected_ty, use_ty)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !fudge_equals_found_ty(init_ty) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +311,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
// If the type is not constrained in a way making it not possible to
|
// If the type is not constrained in a way making it not possible to
|
||||||
// equate with `expected_ty` by this point, skip.
|
// equate with `expected_ty` by this point, skip.
|
||||||
if fudge_equals_found_ty(next_use_ty) {
|
if self.can_eq(self.param_env, expected_ty, next_use_ty.fold_with(&mut fudger)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,26 +320,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&& rcvr.hir_id == binding.hir_id
|
&& rcvr.hir_id == binding.hir_id
|
||||||
{
|
{
|
||||||
let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; };
|
let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; };
|
||||||
let rcvr_ty = fudge_ty(rcvr_ty);
|
let rcvr_ty = rcvr_ty.fold_with(&mut fudger);
|
||||||
if let Ok(method) =
|
let Ok(method) =
|
||||||
self.lookup_method(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args)
|
self.lookup_method(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args)
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE: For future removers of `fudge_inference_if_ok`, you
|
||||||
|
// can replace this with another call to `lookup_method` but
|
||||||
|
// using `expected_ty` as the rcvr.
|
||||||
|
let ideal_method_sig: Result<_, TypeError<'tcx>> = self.fudge_inference_if_ok(|| {
|
||||||
|
let _ = self.at(&ObligationCause::dummy(), self.param_env).eq(rcvr_ty, expected_ty)?;
|
||||||
|
Ok(method.sig)
|
||||||
|
});
|
||||||
|
|
||||||
|
for (idx, (expected_arg_ty, arg_expr)) in
|
||||||
|
std::iter::zip(&method.sig.inputs()[1..], args).enumerate()
|
||||||
{
|
{
|
||||||
for (expected_arg_ty, arg_expr) in std::iter::zip(&method.sig.inputs()[1..], args) {
|
let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; };
|
||||||
let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; };
|
let arg_ty = arg_ty.fold_with(&mut fudger);
|
||||||
let arg_ty = fudge_ty(arg_ty);
|
let _ = self.try_coerce(
|
||||||
let _ = self.try_coerce(arg_expr, arg_ty, *expected_arg_ty, AllowTwoPhase::No, None);
|
arg_expr,
|
||||||
if !self.can_eq(self.param_env, rcvr_ty, expected_ty) {
|
arg_ty,
|
||||||
err.span_label(
|
*expected_arg_ty,
|
||||||
arg_expr.span,
|
AllowTwoPhase::No,
|
||||||
format!("this argument has type `{arg_ty}`...")
|
None,
|
||||||
);
|
);
|
||||||
err.span_label(
|
if self.can_eq(self.param_env, rcvr_ty, expected_ty) {
|
||||||
binding.span,
|
continue;
|
||||||
format!("... which constrains `{ident}` to have type `{next_use_ty}`")
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
err.span_label(
|
||||||
|
arg_expr.span,
|
||||||
|
format!("this argument has type `{arg_ty}`..."),
|
||||||
|
);
|
||||||
|
err.span_label(
|
||||||
|
binding.span,
|
||||||
|
format!(
|
||||||
|
"... which constrains `{ident}` to have type `{next_use_ty}`"
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if let Ok(ideal_method_sig) = ideal_method_sig {
|
||||||
|
self.emit_type_mismatch_suggestions(
|
||||||
|
err,
|
||||||
|
arg_expr,
|
||||||
|
arg_ty,
|
||||||
|
ideal_method_sig.inputs()[idx + 1],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ fn main() {
|
||||||
let mut foo = vec![];
|
let mut foo = vec![];
|
||||||
baz(&foo);
|
baz(&foo);
|
||||||
for i in &v {
|
for i in &v {
|
||||||
foo.push(i);
|
foo.push(*i);
|
||||||
}
|
}
|
||||||
baz(&foo);
|
baz(&foo);
|
||||||
bar(foo); //~ ERROR E0308
|
bar(foo); //~ ERROR E0308
|
||||||
|
|
|
@ -18,6 +18,10 @@ note: function defined here
|
||||||
|
|
|
|
||||||
LL | fn bar(_: Vec<i32>) {}
|
LL | fn bar(_: Vec<i32>) {}
|
||||||
| ^^^ -----------
|
| ^^^ -----------
|
||||||
|
help: consider dereferencing the borrow
|
||||||
|
|
|
||||||
|
LL | foo.push(*i);
|
||||||
|
| +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue