fix misleading type annotation diagonstics
This solves the method call part of issue https://github.com/rust-lang/rust/issues/69455 I added a `target_span` field so as to pin down the exact location of the error. We need a dedicated field `found_exact_method_call` to prioritize situations like the test case `issue-69455.rs`. If we reuse `found_method_call`, `found_local_pattern` will show up first. We can not move `found_method_call` up, it is undesirable in various situations.
This commit is contained in:
parent
39b62533c7
commit
3ae974f025
@ -17,23 +17,27 @@
|
|||||||
struct FindHirNodeVisitor<'a, 'tcx> {
|
struct FindHirNodeVisitor<'a, 'tcx> {
|
||||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||||
target: GenericArg<'tcx>,
|
target: GenericArg<'tcx>,
|
||||||
|
target_span: Span,
|
||||||
found_node_ty: Option<Ty<'tcx>>,
|
found_node_ty: Option<Ty<'tcx>>,
|
||||||
found_local_pattern: Option<&'tcx Pat<'tcx>>,
|
found_local_pattern: Option<&'tcx Pat<'tcx>>,
|
||||||
found_arg_pattern: Option<&'tcx Pat<'tcx>>,
|
found_arg_pattern: Option<&'tcx Pat<'tcx>>,
|
||||||
found_closure: Option<&'tcx Expr<'tcx>>,
|
found_closure: Option<&'tcx Expr<'tcx>>,
|
||||||
found_method_call: Option<&'tcx Expr<'tcx>>,
|
found_method_call: Option<&'tcx Expr<'tcx>>,
|
||||||
|
found_exact_method_call: Option<&'tcx Expr<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
|
||||||
fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>) -> Self {
|
fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self {
|
||||||
Self {
|
Self {
|
||||||
infcx,
|
infcx,
|
||||||
target,
|
target,
|
||||||
|
target_span,
|
||||||
found_node_ty: None,
|
found_node_ty: None,
|
||||||
found_local_pattern: None,
|
found_local_pattern: None,
|
||||||
found_arg_pattern: None,
|
found_arg_pattern: None,
|
||||||
found_closure: None,
|
found_closure: None,
|
||||||
found_method_call: None,
|
found_method_call: None,
|
||||||
|
found_exact_method_call: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +107,17 @@ fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||||
|
if let ExprKind::MethodCall(_, call_span, exprs) = expr.kind {
|
||||||
|
if call_span == self.target_span
|
||||||
|
&& Some(self.target)
|
||||||
|
== self.infcx.in_progress_tables.and_then(|tables| {
|
||||||
|
tables.borrow().node_type_opt(exprs.first().unwrap().hir_id).map(Into::into)
|
||||||
|
})
|
||||||
|
{
|
||||||
|
self.found_exact_method_call = Some(&expr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if self.node_ty_contains_target(expr.hir_id).is_some() {
|
if self.node_ty_contains_target(expr.hir_id).is_some() {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::Closure(..) => self.found_closure = Some(&expr),
|
ExprKind::Closure(..) => self.found_closure = Some(&expr),
|
||||||
@ -234,7 +249,7 @@ pub fn need_type_info_err(
|
|||||||
let ty = self.resolve_vars_if_possible(&ty);
|
let ty = self.resolve_vars_if_possible(&ty);
|
||||||
let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
|
let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
|
||||||
|
|
||||||
let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into());
|
let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span);
|
||||||
let ty_to_string = |ty: Ty<'tcx>| -> String {
|
let ty_to_string = |ty: Ty<'tcx>| -> String {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
|
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
|
||||||
@ -287,14 +302,15 @@ pub fn need_type_info_err(
|
|||||||
(!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
|
(!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty_msg = match local_visitor.found_node_ty {
|
let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
|
||||||
Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => {
|
(_, Some(_)) => String::new(),
|
||||||
|
(Some(ty::TyS { kind: ty::Closure(_, substs), .. }), _) => {
|
||||||
let fn_sig = substs.as_closure().sig();
|
let fn_sig = substs.as_closure().sig();
|
||||||
let args = closure_args(&fn_sig);
|
let args = closure_args(&fn_sig);
|
||||||
let ret = fn_sig.output().skip_binder().to_string();
|
let ret = fn_sig.output().skip_binder().to_string();
|
||||||
format!(" for the closure `fn({}) -> {}`", args, ret)
|
format!(" for the closure `fn({}) -> {}`", args, ret)
|
||||||
}
|
}
|
||||||
Some(ty) if is_named_and_not_impl_trait(ty) => {
|
(Some(ty), _) if is_named_and_not_impl_trait(ty) => {
|
||||||
let ty = ty_to_string(ty);
|
let ty = ty_to_string(ty);
|
||||||
format!(" for `{}`", ty)
|
format!(" for `{}`", ty)
|
||||||
}
|
}
|
||||||
@ -370,7 +386,37 @@ pub fn need_type_info_err(
|
|||||||
_ => "a type".to_string(),
|
_ => "a type".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(pattern) = local_visitor.found_arg_pattern {
|
if let Some(e) = local_visitor.found_exact_method_call {
|
||||||
|
if let ExprKind::MethodCall(segment, ..) = &e.kind {
|
||||||
|
// Suggest specifying type params or point out the return type of the call:
|
||||||
|
//
|
||||||
|
// error[E0282]: type annotations needed
|
||||||
|
// --> $DIR/type-annotations-needed-expr.rs:2:39
|
||||||
|
// |
|
||||||
|
// LL | let _ = x.into_iter().sum() as f64;
|
||||||
|
// | ^^^
|
||||||
|
// | |
|
||||||
|
// | cannot infer type for `S`
|
||||||
|
// | help: consider specifying the type argument in
|
||||||
|
// | the method call: `sum::<S>`
|
||||||
|
// |
|
||||||
|
// = note: type must be known at this point
|
||||||
|
//
|
||||||
|
// or
|
||||||
|
//
|
||||||
|
// error[E0282]: type annotations needed
|
||||||
|
// --> $DIR/issue-65611.rs:59:20
|
||||||
|
// |
|
||||||
|
// LL | let x = buffer.last().unwrap().0.clone();
|
||||||
|
// | -------^^^^--
|
||||||
|
// | | |
|
||||||
|
// | | cannot infer type for `T`
|
||||||
|
// | this method call resolves to `std::option::Option<&T>`
|
||||||
|
// |
|
||||||
|
// = note: type must be known at this point
|
||||||
|
self.annotate_method_call(segment, e, &mut err);
|
||||||
|
}
|
||||||
|
} else if let Some(pattern) = local_visitor.found_arg_pattern {
|
||||||
// We don't want to show the default label for closures.
|
// We don't want to show the default label for closures.
|
||||||
//
|
//
|
||||||
// So, before clearing, the output would look something like this:
|
// So, before clearing, the output would look something like this:
|
||||||
|
30
src/test/ui/issues/issue-69455.rs
Normal file
30
src/test/ui/issues/issue-69455.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Regression test for #69455: projection predicate was not satisfied.
|
||||||
|
// Compiler should indicate the correct location of the
|
||||||
|
// unsatisfied projection predicate
|
||||||
|
|
||||||
|
pub trait Test<Rhs = Self> {
|
||||||
|
type Output;
|
||||||
|
|
||||||
|
fn test(self, rhs: Rhs) -> Self::Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Test<u32> for u64 {
|
||||||
|
type Output = u64;
|
||||||
|
|
||||||
|
fn test(self, other: u32) -> u64 {
|
||||||
|
self + (other as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Test<u64> for u64 {
|
||||||
|
type Output = u64;
|
||||||
|
|
||||||
|
fn test(self, other: u64) -> u64 {
|
||||||
|
(self + other) as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let xs: Vec<u64> = vec![1, 2, 3];
|
||||||
|
println!("{}", 23u64.test(xs.iter().sum())); //~ ERROR: type annotations needed [E0284]
|
||||||
|
}
|
17
src/test/ui/issues/issue-69455.stderr
Normal file
17
src/test/ui/issues/issue-69455.stderr
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
error[E0284]: type annotations needed
|
||||||
|
--> $DIR/issue-69455.rs:29:26
|
||||||
|
|
|
||||||
|
LL | type Output;
|
||||||
|
| ------------ `<Self as Test<Rhs>>::Output` defined here
|
||||||
|
...
|
||||||
|
LL | println!("{}", 23u64.test(xs.iter().sum()));
|
||||||
|
| ------^^^^-----------------
|
||||||
|
| | |
|
||||||
|
| | cannot infer type for type `u64`
|
||||||
|
| this method call resolves to `<Self as Test<Rhs>>::Output`
|
||||||
|
|
|
||||||
|
= note: cannot satisfy `<u64 as Test<_>>::Output == _`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0284`.
|
Loading…
Reference in New Issue
Block a user