diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 665dc8b6a2f2a..f4c4d43101a51 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1,11 +1,9 @@ use crate::FnCtxt; use rustc_ast::util::parser::PREC_POSTFIX; -use rustc_data_structures::fx::FxHashMap; use rustc_errors::MultiSpan; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::CtorKind; -use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{is_range_literal, Node}; use rustc_infer::infer::InferOk; @@ -13,14 +11,11 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder}; -use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; -use rustc_middle::ty::relate::TypeRelation; -use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeVisitable}; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{BytePos, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::traits::error_reporting::method_chain::CollectAllMismatches; use rustc_trait_selection::traits::ObligationCause; use super::method::probe; @@ -45,7 +40,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.annotate_alternative_method_deref(err, expr, error); // Use `||` to give these suggestions a precedence - let suggested = self.suggest_missing_parentheses(err, expr) + let _ = self.suggest_missing_parentheses(err, expr) || self.suggest_remove_last_method_call(err, expr, expected) || self.suggest_associated_const(err, expr, expected) || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr) @@ -60,9 +55,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_clone_for_ref(err, expr, expr_ty, expected) || self.suggest_into(err, expr, expr_ty, expected) || self.suggest_floating_point_literal(err, expr, expected); - if !suggested { - self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected); - } } pub fn emit_coerce_suggestions( @@ -216,216 +208,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (expected, Some(err)) } - pub fn point_at_expr_source_of_inferred_type( - &self, - err: &mut Diagnostic, - expr: &hir::Expr<'_>, - found: Ty<'tcx>, - expected: Ty<'tcx>, - ) -> bool { - let map = self.tcx.hir(); - - let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else { return false; }; - let [hir::PathSegment { ident, args: None, .. }] = p.segments else { return false; }; - let hir::def::Res::Local(hir_id) = p.res else { return false; }; - let Some(hir::Node::Pat(pat)) = map.find(hir_id) else { return false; }; - let Some(hir::Node::Local(hir::Local { - ty: None, - init: Some(init), - .. - })) = map.find_parent(pat.hir_id) else { return false; }; - let Some(ty) = self.node_ty_opt(init.hir_id) else { return false; }; - if ty.is_closure() || init.span.overlaps(expr.span) || pat.span.from_expansion() { - return false; - } - - // Locate all the usages of the relevant binding. - struct FindExprs<'hir> { - hir_id: hir::HirId, - uses: Vec<&'hir hir::Expr<'hir>>, - } - impl<'v> Visitor<'v> for FindExprs<'v> { - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { - if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = ex.kind - && let hir::def::Res::Local(hir_id) = path.res - && hir_id == self.hir_id - { - self.uses.push(ex); - } - hir::intravisit::walk_expr(self, ex); - } - } - - let mut expr_finder = FindExprs { hir_id, uses: vec![] }; - let id = map.get_parent_item(hir_id); - let hir_id: hir::HirId = id.into(); - - let Some(node) = map.find(hir_id) else { return false; }; - let Some(body_id) = node.body_id() else { return false; }; - let body = map.body(body_id); - expr_finder.visit_expr(body.value); - // Hack to make equality checks on types with inference variables and regions useful. - let mut eraser = BottomUpFolder { - tcx: self.tcx, - lt_op: |_| self.tcx.lifetimes.re_erased, - ct_op: |c| c, - ty_op: |t| match *t.kind() { - ty::Infer(ty::TyVar(vid)) => self.tcx.mk_ty_infer(ty::TyVar(self.root_var(vid))), - ty::Infer(ty::IntVar(_)) => { - self.tcx.mk_ty_infer(ty::IntVar(ty::IntVid { index: 0 })) - } - ty::Infer(ty::FloatVar(_)) => { - self.tcx.mk_ty_infer(ty::FloatVar(ty::FloatVid { index: 0 })) - } - _ => t, - }, - }; - let mut prev = eraser.fold_ty(ty); - let mut prev_span = None; - - for binding in expr_finder.uses { - // In every expression where the binding is referenced, we will look at that - // expression's type and see if it is where the incorrect found type was fully - // "materialized" and point at it. We will also try to provide a suggestion there. - if let Some(hir::Node::Expr(expr) - | hir::Node::Stmt(hir::Stmt { - kind: hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr), - .. - })) = &map.find_parent(binding.hir_id) - && let hir::ExprKind::MethodCall(segment, rcvr, args, _span) = expr.kind - && rcvr.hir_id == binding.hir_id - && let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(expr.hir_id) - { - // We special case methods, because they can influence inference through the - // call's arguments and we can provide a more explicit span. - let sig = self.tcx.fn_sig(def_id); - let def_self_ty = sig.input(0).skip_binder(); - let rcvr_ty = self.node_ty(rcvr.hir_id); - // Get the evaluated type *after* calling the method call, so that the influence - // of the arguments can be reflected in the receiver type. The receiver - // expression has the type *before* theis analysis is done. - let ty = match self.lookup_probe_for_diagnostic( - segment.ident, - rcvr_ty, - expr, - probe::ProbeScope::TraitsInScope, - None, - ) { - Ok(pick) => pick.self_ty, - Err(_) => rcvr_ty, - }; - // Remove one layer of references to account for `&mut self` and - // `&self`, so that we can compare it against the binding. - let (ty, def_self_ty) = match (ty.kind(), def_self_ty.kind()) { - (ty::Ref(_, ty, a), ty::Ref(_, self_ty, b)) if a == b => (*ty, *self_ty), - _ => (ty, def_self_ty), - }; - let mut param_args = FxHashMap::default(); - let mut param_expected = FxHashMap::default(); - let mut param_found = FxHashMap::default(); - if self.can_eq(self.param_env, ty, found).is_ok() { - // We only point at the first place where the found type was inferred. - for (i, param_ty) in sig.inputs().skip_binder().iter().skip(1).enumerate() { - if def_self_ty.contains(*param_ty) && let ty::Param(_) = param_ty.kind() { - // We found an argument that references a type parameter in `Self`, - // so we assume that this is the argument that caused the found - // type, which we know already because of `can_eq` above was first - // inferred in this method call. - let arg = &args[i]; - let arg_ty = self.node_ty(arg.hir_id); - err.span_label( - arg.span, - &format!( - "this is of type `{arg_ty}`, which causes `{ident}` to be \ - inferred as `{ty}`", - ), - ); - param_args.insert(param_ty, (arg, arg_ty)); - } - } - } - - // Here we find, for a type param `T`, the type that `T` is in the current - // method call *and* in the original expected type. That way, we can see if we - // can give any structured suggestion for the function argument. - let mut c = CollectAllMismatches { - infcx: &self.infcx, - param_env: self.param_env, - errors: vec![], - }; - let _ = c.relate(def_self_ty, ty); - for error in c.errors { - if let TypeError::Sorts(error) = error { - param_found.insert(error.expected, error.found); - } - } - c.errors = vec![]; - let _ = c.relate(def_self_ty, expected); - for error in c.errors { - if let TypeError::Sorts(error) = error { - param_expected.insert(error.expected, error.found); - } - } - for (param, (arg, arg_ty)) in param_args.iter() { - let Some(expected) = param_expected.get(param) else { continue; }; - let Some(found) = param_found.get(param) else { continue; }; - if self.can_eq(self.param_env, *arg_ty, *found).is_err() { continue; } - self.emit_coerce_suggestions(err, arg, *found, *expected, None, None); - } - - let ty = eraser.fold_ty(ty); - if ty.references_error() { - break; - } - if ty != prev - && param_args.is_empty() - && self.can_eq(self.param_env, ty, found).is_ok() - { - // We only point at the first place where the found type was inferred. - err.span_label( - segment.ident.span, - with_forced_trimmed_paths!(format!( - "here the type of `{ident}` is inferred to be `{ty}`", - )), - ); - break; - } else if !param_args.is_empty() { - break; - } - prev = ty; - } else { - let ty = eraser.fold_ty(self.node_ty(binding.hir_id)); - if ty.references_error() { - break; - } - if ty != prev - && let Some(span) = prev_span - && self.can_eq(self.param_env, ty, found).is_ok() - { - // We only point at the first place where the found type was inferred. - // We use the *previous* span because if the type is known *here* it means - // it was *evaluated earlier*. We don't do this for method calls because we - // evaluate the method's self type eagerly, but not in any other case. - err.span_label( - span, - with_forced_trimmed_paths!(format!( - "here the type of `{ident}` is inferred to be `{ty}`", - )), - ); - break; - } - prev = ty; - } - if binding.hir_id == expr.hir_id { - // Do not look at expressions that come after the expression we were originally - // evaluating and had a type error. - break; - } - prev_span = Some(binding.span); - } - true - } - fn annotate_expected_due_to_let_ty( &self, err: &mut Diagnostic, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index c9609e6943981..2d841d53f9ca4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -798,18 +798,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { full_call_span, format!("arguments to this {} are incorrect", call_name), ); - if let (Some(callee_ty), hir::ExprKind::MethodCall(_, rcvr, _, _)) = - (callee_ty, &call_expr.kind) - { - // Type that would have accepted this argument if it hadn't been inferred earlier. - // FIXME: We leave an inference variable for now, but it'd be nice to get a more - // specific type to increase the accuracy of the diagnostic. - let expected = self.infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: full_call_span, - }); - self.point_at_expr_source_of_inferred_type(&mut err, rcvr, expected, callee_ty); - } // Call out where the function is defined self.label_fn_like( &mut err, diff --git a/tests/ui/type/type-check/assignment-in-if.stderr b/tests/ui/type/type-check/assignment-in-if.stderr index de133e5599cf9..9f4558adab150 100644 --- a/tests/ui/type/type-check/assignment-in-if.stderr +++ b/tests/ui/type/type-check/assignment-in-if.stderr @@ -67,9 +67,6 @@ LL | x == 5 error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:44:18 | -LL | if y = (Foo { foo: x }) { - | - here the type of `x` is inferred to be `usize` -... LL | if x == x && x = x && x == x { | ------ ^ expected `bool`, found `usize` | | @@ -78,9 +75,6 @@ LL | if x == x && x = x && x == x { error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:44:22 | -LL | if y = (Foo { foo: x }) { - | - here the type of `x` is inferred to be `usize` -... LL | if x == x && x = x && x == x { | ^ expected `bool`, found `usize` @@ -98,9 +92,6 @@ LL | if x == x && x == x && x == x { error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:51:28 | -LL | if y = (Foo { foo: x }) { - | - here the type of `x` is inferred to be `usize` -... LL | if x == x && x == x && x = x { | ---------------- ^ expected `bool`, found `usize` | | diff --git a/tests/ui/type/type-check/point-at-inference-2.stderr b/tests/ui/type/type-check/point-at-inference-2.stderr index 13227c5e245bd..1368aba0d467c 100644 --- a/tests/ui/type/type-check/point-at-inference-2.stderr +++ b/tests/ui/type/type-check/point-at-inference-2.stderr @@ -17,9 +17,6 @@ LL | fn bar(_: Vec) {} error[E0308]: mismatched types --> $DIR/point-at-inference-2.rs:9:9 | -LL | baz(&v); - | - here the type of `v` is inferred to be `Vec<&i32>` -LL | baz(&v); LL | bar(v); | --- ^ expected `i32`, found `&i32` | | @@ -36,8 +33,6 @@ LL | fn bar(_: Vec) {} error[E0308]: mismatched types --> $DIR/point-at-inference-2.rs:12:9 | -LL | baz(&v); - | - here the type of `v` is inferred to be `Vec<&i32>` LL | bar(v); | --- ^ expected `i32`, found `&i32` | | diff --git a/tests/ui/type/type-check/point-at-inference-3.fixed b/tests/ui/type/type-check/point-at-inference-3.fixed index 1a960133ceba9..44c057c0d3b92 100644 --- a/tests/ui/type/type-check/point-at-inference-3.fixed +++ b/tests/ui/type/type-check/point-at-inference-3.fixed @@ -2,7 +2,6 @@ fn main() { let mut v = Vec::new(); v.push(0i32); - //~^ NOTE this is of type `i32`, which causes `v` to be inferred as `Vec` v.push(0); v.push(1i32); //~ ERROR mismatched types //~^ NOTE expected `i32`, found `u32` diff --git a/tests/ui/type/type-check/point-at-inference-3.rs b/tests/ui/type/type-check/point-at-inference-3.rs index 92910ae1a3114..e7ae543848713 100644 --- a/tests/ui/type/type-check/point-at-inference-3.rs +++ b/tests/ui/type/type-check/point-at-inference-3.rs @@ -2,7 +2,6 @@ fn main() { let mut v = Vec::new(); v.push(0i32); - //~^ NOTE this is of type `i32`, which causes `v` to be inferred as `Vec` v.push(0); v.push(1u32); //~ ERROR mismatched types //~^ NOTE expected `i32`, found `u32` diff --git a/tests/ui/type/type-check/point-at-inference-3.stderr b/tests/ui/type/type-check/point-at-inference-3.stderr index 999c3148362f6..d7936e39cefc2 100644 --- a/tests/ui/type/type-check/point-at-inference-3.stderr +++ b/tests/ui/type/type-check/point-at-inference-3.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types - --> $DIR/point-at-inference-3.rs:7:12 + --> $DIR/point-at-inference-3.rs:6:12 | -LL | v.push(0i32); - | ---- this is of type `i32`, which causes `v` to be inferred as `Vec` -... LL | v.push(1u32); | ---- ^^^^ expected `i32`, found `u32` | | diff --git a/tests/ui/type/type-check/point-at-inference.fixed b/tests/ui/type/type-check/point-at-inference.fixed deleted file mode 100644 index f41fbe59fba6c..0000000000000 --- a/tests/ui/type/type-check/point-at-inference.fixed +++ /dev/null @@ -1,13 +0,0 @@ -// run-rustfix -fn bar(_: Vec) {} -fn baz(_: &impl std::any::Any) {} -fn main() { - let v = vec![1, 2, 3, 4, 5]; - let mut foo = vec![]; - baz(&foo); - for i in &v { - foo.push(*i); - } - baz(&foo); - bar(foo); //~ ERROR E0308 -} diff --git a/tests/ui/type/type-check/point-at-inference.rs b/tests/ui/type/type-check/point-at-inference.rs index 6419e42e70d12..5c46dd4ed807e 100644 --- a/tests/ui/type/type-check/point-at-inference.rs +++ b/tests/ui/type/type-check/point-at-inference.rs @@ -1,4 +1,3 @@ -// run-rustfix fn bar(_: Vec) {} fn baz(_: &impl std::any::Any) {} fn main() { diff --git a/tests/ui/type/type-check/point-at-inference.stderr b/tests/ui/type/type-check/point-at-inference.stderr index 70428fe841b9c..2e17e5c5f58ba 100644 --- a/tests/ui/type/type-check/point-at-inference.stderr +++ b/tests/ui/type/type-check/point-at-inference.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types - --> $DIR/point-at-inference.rs:12:9 + --> $DIR/point-at-inference.rs:11:9 | -LL | foo.push(i); - | - this is of type `&{integer}`, which causes `foo` to be inferred as `Vec<&{integer}>` -... LL | bar(foo); | --- ^^^ expected `i32`, found `&{integer}` | | @@ -12,14 +9,10 @@ LL | bar(foo); = note: expected struct `Vec` found struct `Vec<&{integer}>` note: function defined here - --> $DIR/point-at-inference.rs:2:4 + --> $DIR/point-at-inference.rs:1:4 | LL | fn bar(_: Vec) {} | ^^^ ----------- -help: consider dereferencing the borrow - | -LL | foo.push(*i); - | + error: aborting due to previous error