From e72c45ad987b296baee79865b7e2ca00c518fb8b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 2 Mar 2023 23:23:07 +0000 Subject: [PATCH] Point at which arg causes a binding to be constrained --- compiler/rustc_hir_typeck/src/demand.rs | 63 +++++++++++++++---- .../type/type-check/point-at-inference.stderr | 4 +- tests/ui/typeck/issue-107775.stderr | 4 +- 3 files changed, 57 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 0c4f73e0db0e..0d3e4bde497f 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -259,10 +259,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir.body(hir.maybe_body_owned_by(self.body_id).expect("expected item to have body")); expr_finder.visit_expr(body.value); - let fudge_equals_found_ty = |use_ty: Ty<'tcx>| { + let fudge_ty = |ty: Ty<'tcx>| { use rustc_infer::infer::type_variable::*; use rustc_middle::infer::unify_key::*; - let use_ty = use_ty.fold_with(&mut BottomUpFolder { + ty.fold_with(&mut BottomUpFolder { tcx: self.tcx, ty_op: |ty| { if let ty::Infer(infer) = ty.kind() { @@ -293,7 +293,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ct } }, - }); + }) + }; + + let fudge_equals_found_ty = |use_ty: Ty<'tcx>| { + let use_ty = fudge_ty(use_ty); self.can_eq(self.param_env, expected_ty, use_ty) }; @@ -303,18 +307,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for window in expr_finder.uses.windows(2) { let [binding, next_usage] = *window else { continue; }; - let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else { continue; }; - if !fudge_equals_found_ty(next_use_ty) { - err.span_label( - binding.span, - format!("here the type of `{ident}` is inferred to be `{next_use_ty}`"), - ); - return true; - } - if next_usage.hir_id == expr.hir_id { + // Don't go past the binding (always gonna be a nonsense label if so) + if binding.hir_id == expr.hir_id { break; } + + let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else { continue; }; + + // If the type is not constrained in a way making it not possible to + // equate with `expected_ty` by this point, skip. + if fudge_equals_found_ty(next_use_ty) { + continue; + } + + if let hir::Node::Expr(parent_expr) = hir.get_parent(binding.hir_id) + && let hir::ExprKind::MethodCall(segment, rcvr, args, _) = parent_expr.kind + && rcvr.hir_id == binding.hir_id + { + let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; }; + let rcvr_ty = fudge_ty(rcvr_ty); + if let Ok(method) = + self.lookup_method(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args) + { + 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 arg_ty = fudge_ty(arg_ty); + let _ = self.try_coerce(arg_expr, arg_ty, *expected_arg_ty, AllowTwoPhase::No, None); + if !self.can_eq(self.param_env, rcvr_ty, expected_ty) { + 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}`") + ); + return true; + } + } + } + } + + err.span_label( + binding.span, + format!("here the type of `{ident}` is inferred to be `{next_use_ty}`"), + ); + return true; } // We must've not found something that constrained the expr. diff --git a/tests/ui/type/type-check/point-at-inference.stderr b/tests/ui/type/type-check/point-at-inference.stderr index 89c4cd1c3763..5d46368b1fd3 100644 --- a/tests/ui/type/type-check/point-at-inference.stderr +++ b/tests/ui/type/type-check/point-at-inference.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/point-at-inference.rs:12:9 | LL | foo.push(i); - | --- here the type of `foo` is inferred to be `Vec<&{integer}>` + | --- - this argument has type `&{integer}`... + | | + | ... which causes `foo` to have type `Vec<&{integer}>` ... LL | bar(foo); | --- ^^^ expected `Vec`, found `Vec<&{integer}>` diff --git a/tests/ui/typeck/issue-107775.stderr b/tests/ui/typeck/issue-107775.stderr index 39c727bd278b..b97e74b7e53f 100644 --- a/tests/ui/typeck/issue-107775.stderr +++ b/tests/ui/typeck/issue-107775.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/issue-107775.rs:35:16 | LL | map.insert(1, Struct::do_something); - | --- here the type of `map` is inferred to be `HashMap<{integer}, fn(u8) -> Pin + Send>> {::do_something::<'_>}>` + | --- -------------------- this argument has type `fn(u8) -> Pin + Send>> {::do_something::<'_>}`... + | | + | ... which causes `map` to have type `HashMap<{integer}, fn(u8) -> Pin + Send>> {::do_something::<'_>}>` LL | Self { map } | ^^^ expected `HashMap Pin<...>>`, found `HashMap<{integer}, ...>` |