From cd3204d1a272dc4739a5f86546620287941aa6e7 Mon Sep 17 00:00:00 2001 From: Michael Goulet <michael@errs.io> Date: Wed, 20 Jul 2022 03:05:14 +0000 Subject: [PATCH] Normalize the arg spans to be within the call span --- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 26 +++++++++++++------ src/test/ui/inference/deref-suggestion.rs | 3 ++- src/test/ui/inference/deref-suggestion.stderr | 24 +++++++---------- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index e3db70845ddf1..64f931aca95f4 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -481,6 +481,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.set_tainted_by_errors(); let tcx = self.tcx; + // Get the argument span in the context of the call span so that + // suggestions and labels are (more) correct when an arg is a + // macro invocation. + let normalize_span = |span: Span| -> Span { + let normalized_span = span.find_ancestor_inside(error_span).unwrap_or(span); + // Sometimes macros mess up the spans, so do not normalize the + // arg span to equal the error span, because that's less useful + // than pointing out the arg expr in the wrong context. + if normalized_span.source_equal(error_span) { span } else { normalized_span } + }; + // Precompute the provided types and spans, since that's all we typically need for below let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args .iter() @@ -490,7 +501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .borrow() .expr_ty_adjusted_opt(*expr) .unwrap_or_else(|| tcx.ty_error()); - (self.resolve_vars_if_possible(ty), expr.span) + (self.resolve_vars_if_possible(ty), normalize_span(expr.span)) }) .collect(); let callee_expr = match &call_expr.peel_blocks().kind { @@ -600,11 +611,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Take some care with spans, so we don't suggest wrapping a macro's // innards in parenthesis, for example. if satisfied - && let Some(lo) = - provided_args[mismatch_idx.into()].span.find_ancestor_inside(error_span) - && let Some(hi) = provided_args[(mismatch_idx + tys.len() - 1).into()] - .span - .find_ancestor_inside(error_span) + && let Some((_, lo)) = + provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx)) + && let Some((_, hi)) = + provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx + tys.len() - 1)) { let mut err; if tys.len() == 1 { @@ -612,7 +622,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // so don't do anything special here. err = self.report_and_explain_type_error( TypeTrace::types( - &self.misc(lo), + &self.misc(*lo), true, formal_and_expected_inputs[mismatch_idx.into()].1, provided_arg_tys[mismatch_idx.into()].0, @@ -1052,7 +1062,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let suggestion_text = if let Some(provided_idx) = provided_idx && let (_, provided_span) = provided_arg_tys[*provided_idx] && let Ok(arg_text) = - source_map.span_to_snippet(provided_span.source_callsite()) + source_map.span_to_snippet(provided_span) { arg_text } else { diff --git a/src/test/ui/inference/deref-suggestion.rs b/src/test/ui/inference/deref-suggestion.rs index 4fd695585ba06..0d8e7289dc8a2 100644 --- a/src/test/ui/inference/deref-suggestion.rs +++ b/src/test/ui/inference/deref-suggestion.rs @@ -1,5 +1,5 @@ macro_rules! borrow { - ($x:expr) => { &$x } //~ ERROR mismatched types + ($x:expr) => { &$x } } fn foo(_: String) {} @@ -32,6 +32,7 @@ fn main() { foo(&mut "aaa".to_owned()); //~^ ERROR mismatched types foo3(borrow!(0)); + //~^ ERROR mismatched types foo4(&0); assert_eq!(3i32, &3i32); //~^ ERROR mismatched types diff --git a/src/test/ui/inference/deref-suggestion.stderr b/src/test/ui/inference/deref-suggestion.stderr index e763e17e51786..d729f2d682a61 100644 --- a/src/test/ui/inference/deref-suggestion.stderr +++ b/src/test/ui/inference/deref-suggestion.stderr @@ -70,13 +70,10 @@ LL + foo("aaa".to_owned()); | error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:2:20 + --> $DIR/deref-suggestion.rs:34:10 | -LL | ($x:expr) => { &$x } - | ^^^ expected `u32`, found `&{integer}` -... LL | foo3(borrow!(0)); - | ---- ---------- in this macro invocation + | ---- ^^^^^^^^^^ expected `u32`, found `&{integer}` | | | arguments to this function are incorrect | @@ -85,10 +82,9 @@ note: function defined here | LL | fn foo3(_: u32) {} | ^^^^ ------ - = note: this error originates in the macro `borrow` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:36:5 + --> $DIR/deref-suggestion.rs:37:5 | LL | assert_eq!(3i32, &3i32); | ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `&i32` @@ -96,7 +92,7 @@ LL | assert_eq!(3i32, &3i32); = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:39:17 + --> $DIR/deref-suggestion.rs:40:17 | LL | let s = S { u }; | ^ @@ -105,7 +101,7 @@ LL | let s = S { u }; | help: consider borrowing here: `u: &u` error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:41:20 + --> $DIR/deref-suggestion.rs:42:20 | LL | let s = S { u: u }; | ^ @@ -114,7 +110,7 @@ LL | let s = S { u: u }; | help: consider borrowing here: `&u` error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:44:17 + --> $DIR/deref-suggestion.rs:45:17 | LL | let r = R { i }; | ^ expected `u32`, found `&{integer}` @@ -125,7 +121,7 @@ LL | let r = R { i: *i }; | ++++ error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:46:20 + --> $DIR/deref-suggestion.rs:47:20 | LL | let r = R { i: i }; | ^ expected `u32`, found `&{integer}` @@ -136,7 +132,7 @@ LL | let r = R { i: *i }; | + error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:55:9 + --> $DIR/deref-suggestion.rs:56:9 | LL | b | ^ expected `i32`, found `&{integer}` @@ -147,7 +143,7 @@ LL | *b | + error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:63:9 + --> $DIR/deref-suggestion.rs:64:9 | LL | b | ^ expected `i32`, found `&{integer}` @@ -158,7 +154,7 @@ LL | *b | + error[E0308]: `if` and `else` have incompatible types - --> $DIR/deref-suggestion.rs:68:12 + --> $DIR/deref-suggestion.rs:69:12 | LL | let val = if true { | _______________-