Auto merge of #96155 - jackh726:param-heuristics-followup, r=estebank
Followups for method call error change Each commit is self-contained. Fixes most of the followup reviews from that PR. r? `@estebank`
This commit is contained in:
commit
030c886c29
44 changed files with 265 additions and 312 deletions
|
@ -59,7 +59,7 @@ pub fn check_legal_trait_for_method_call(
|
|||
|
||||
enum CallStep<'tcx> {
|
||||
Builtin(Ty<'tcx>),
|
||||
DeferredClosure(ty::FnSig<'tcx>),
|
||||
DeferredClosure(DefId, ty::FnSig<'tcx>),
|
||||
/// E.g., enum variant constructors.
|
||||
Overloaded(MethodCallee<'tcx>),
|
||||
}
|
||||
|
@ -107,8 +107,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.confirm_builtin_call(call_expr, callee_expr, callee_ty, arg_exprs, expected)
|
||||
}
|
||||
|
||||
Some(CallStep::DeferredClosure(fn_sig)) => {
|
||||
self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig)
|
||||
Some(CallStep::DeferredClosure(def_id, fn_sig)) => {
|
||||
self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, def_id, fn_sig)
|
||||
}
|
||||
|
||||
Some(CallStep::Overloaded(method_callee)) => {
|
||||
|
@ -171,7 +171,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
closure_substs: substs,
|
||||
},
|
||||
);
|
||||
return Some(CallStep::DeferredClosure(closure_sig));
|
||||
return Some(CallStep::DeferredClosure(def_id, closure_sig));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -533,6 +533,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
call_expr: &'tcx hir::Expr<'tcx>,
|
||||
arg_exprs: &'tcx [hir::Expr<'tcx>],
|
||||
expected: Expectation<'tcx>,
|
||||
closure_def_id: DefId,
|
||||
fn_sig: ty::FnSig<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
// `fn_sig` is the *signature* of the closure being called. We
|
||||
|
@ -555,7 +556,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
arg_exprs,
|
||||
fn_sig.c_variadic,
|
||||
TupleArgumentsFlag::TupleArguments,
|
||||
None,
|
||||
Some(closure_def_id),
|
||||
);
|
||||
|
||||
fn_sig.output()
|
||||
|
|
|
@ -24,7 +24,7 @@ use rustc_infer::infer::TypeTrace;
|
|||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{self, Span};
|
||||
|
@ -394,6 +394,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
break 'errors;
|
||||
}
|
||||
|
||||
self.set_tainted_by_errors();
|
||||
|
||||
// The algorithm here is inspired by levenshtein distance and longest common subsequence.
|
||||
// We'll try to detect 4 different types of mistakes:
|
||||
// - An extra parameter has been provided that doesn't satisfy *any* of the other inputs
|
||||
|
@ -502,6 +504,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
TupleMatchFound::Single => {
|
||||
let expected_ty = expected_input_tys[0];
|
||||
let provided_ty = final_arg_types[0].map(|ty| ty.0).unwrap();
|
||||
let expected_ty = self.resolve_vars_if_possible(expected_ty);
|
||||
let provided_ty = self.resolve_vars_if_possible(provided_ty);
|
||||
let cause = &self.misc(provided_args[0].span);
|
||||
let compatibility = demand_compatible(0, &mut final_arg_types);
|
||||
let type_error = match compatibility {
|
||||
|
@ -523,24 +527,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
format!("arguments to this {} are incorrect", call_name),
|
||||
);
|
||||
// Call out where the function is defined
|
||||
if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) {
|
||||
let mut spans: MultiSpan = def_span.into();
|
||||
|
||||
let params = tcx
|
||||
.hir()
|
||||
.get_if_local(def_id)
|
||||
.and_then(|node| node.body_id())
|
||||
.into_iter()
|
||||
.map(|id| tcx.hir().body(id).params)
|
||||
.flatten();
|
||||
|
||||
for param in params {
|
||||
spans.push_span_label(param.span, String::new());
|
||||
}
|
||||
|
||||
let def_kind = tcx.def_kind(def_id);
|
||||
err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
|
||||
}
|
||||
label_fn_like(tcx, &mut err, fn_def_id);
|
||||
err.emit();
|
||||
break 'errors;
|
||||
}
|
||||
|
@ -558,24 +545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
DiagnosticId::Error(err_code.to_owned()),
|
||||
);
|
||||
// Call out where the function is defined
|
||||
if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) {
|
||||
let mut spans: MultiSpan = def_span.into();
|
||||
|
||||
let params = tcx
|
||||
.hir()
|
||||
.get_if_local(def_id)
|
||||
.and_then(|node| node.body_id())
|
||||
.into_iter()
|
||||
.map(|id| tcx.hir().body(id).params)
|
||||
.flatten();
|
||||
|
||||
for param in params {
|
||||
spans.push_span_label(param.span, String::new());
|
||||
}
|
||||
|
||||
let def_kind = tcx.def_kind(def_id);
|
||||
err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
|
||||
}
|
||||
label_fn_like(tcx, &mut err, fn_def_id);
|
||||
err.multipart_suggestion(
|
||||
"use parentheses to construct a tuple",
|
||||
vec![(start, '('.to_string()), (end, ')'.to_string())],
|
||||
|
@ -597,13 +567,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
{
|
||||
let expected_ty = expected_input_tys[*input_idx];
|
||||
let provided_ty = final_arg_types[*input_idx].map(|ty| ty.0).unwrap();
|
||||
let expected_ty = self.resolve_vars_if_possible(expected_ty);
|
||||
let provided_ty = self.resolve_vars_if_possible(provided_ty);
|
||||
let cause = &self.misc(provided_args[*input_idx].span);
|
||||
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
|
||||
let mut err = self.report_and_explain_type_error(trace, error);
|
||||
self.emit_coerce_suggestions(
|
||||
&mut err,
|
||||
&provided_args[*input_idx],
|
||||
final_arg_types[*input_idx].map(|ty| ty.0).unwrap(),
|
||||
provided_ty,
|
||||
final_arg_types[*input_idx].map(|ty| ty.1).unwrap(),
|
||||
None,
|
||||
None,
|
||||
|
@ -613,24 +585,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
format!("arguments to this {} are incorrect", call_name),
|
||||
);
|
||||
// Call out where the function is defined
|
||||
if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) {
|
||||
let mut spans: MultiSpan = def_span.into();
|
||||
|
||||
let params = tcx
|
||||
.hir()
|
||||
.get_if_local(def_id)
|
||||
.and_then(|node| node.body_id())
|
||||
.into_iter()
|
||||
.map(|id| tcx.hir().body(id).params)
|
||||
.flatten();
|
||||
|
||||
for param in params {
|
||||
spans.push_span_label(param.span, String::new());
|
||||
}
|
||||
|
||||
let def_kind = tcx.def_kind(def_id);
|
||||
err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
|
||||
}
|
||||
label_fn_like(tcx, &mut err, fn_def_id);
|
||||
err.emit();
|
||||
break 'errors;
|
||||
}
|
||||
|
@ -678,12 +633,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
match error {
|
||||
Error::Invalid(input_idx, compatibility) => {
|
||||
let expected_ty = expected_input_tys[input_idx];
|
||||
let provided_ty = final_arg_types
|
||||
.get(input_idx)
|
||||
.and_then(|x| x.as_ref())
|
||||
.map(|ty| ty.0)
|
||||
.unwrap_or(tcx.ty_error());
|
||||
let expected_ty = self.resolve_vars_if_possible(expected_ty);
|
||||
let provided_ty = self.resolve_vars_if_possible(provided_ty);
|
||||
if let Compatibility::Incompatible(error) = &compatibility {
|
||||
let provided_ty = final_arg_types
|
||||
.get(input_idx)
|
||||
.and_then(|x| x.as_ref())
|
||||
.map(|ty| ty.0)
|
||||
.unwrap_or(tcx.ty_error());
|
||||
let cause = &self.misc(
|
||||
provided_args.get(input_idx).map(|i| i.span).unwrap_or(call_span),
|
||||
);
|
||||
|
@ -948,24 +905,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// Call out where the function is defined
|
||||
if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) {
|
||||
let mut spans: MultiSpan = def_span.into();
|
||||
|
||||
let params = tcx
|
||||
.hir()
|
||||
.get_if_local(def_id)
|
||||
.and_then(|node| node.body_id())
|
||||
.into_iter()
|
||||
.flat_map(|id| tcx.hir().body(id).params)
|
||||
;
|
||||
|
||||
for param in params {
|
||||
spans.push_span_label(param.span, String::new());
|
||||
}
|
||||
|
||||
let def_kind = tcx.def_kind(def_id);
|
||||
err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
|
||||
}
|
||||
label_fn_like(tcx, &mut err, fn_def_id);
|
||||
|
||||
// And add a suggestion block for all of the parameters
|
||||
let suggestion_text = match suggestion_text {
|
||||
|
@ -1790,3 +1730,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn label_fn_like<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>,
|
||||
def_id: Option<DefId>,
|
||||
) {
|
||||
let Some(def_id) = def_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(def_span) = tcx.def_ident_span(def_id) {
|
||||
let mut spans: MultiSpan = def_span.into();
|
||||
|
||||
let params = tcx
|
||||
.hir()
|
||||
.get_if_local(def_id)
|
||||
.and_then(|node| node.body_id())
|
||||
.into_iter()
|
||||
.map(|id| tcx.hir().body(id).params)
|
||||
.flatten();
|
||||
|
||||
for param in params {
|
||||
spans.push_span_label(param.span, String::new());
|
||||
}
|
||||
|
||||
let def_kind = tcx.def_kind(def_id);
|
||||
err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
|
||||
} else {
|
||||
match tcx.hir().get_if_local(def_id) {
|
||||
Some(hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure(_, _, _, span, ..),
|
||||
..
|
||||
})) => {
|
||||
let spans: MultiSpan = (*span).into();
|
||||
|
||||
// Note: We don't point to param spans here because they overlap
|
||||
// with the closure span itself
|
||||
|
||||
err.span_note(spans, "closure defined here");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue