diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index ede2ed5169f..dc49ff90f34 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1629,7 +1629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - for error in errors { + 'outer: for error in errors { // Only if the cause is somewhere inside the expression we want try to point at arg. // Otherwise, it means that the cause is somewhere else and we should not change // anything because we can break the correct span. @@ -1671,10 +1671,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => continue, }; let self_ = self.resolve_vars_if_possible(self_); + let ty_matches_self = |ty: Ty<'tcx>| ty.walk().any(|arg| arg == self_); + + let typeck_results = self.typeck_results.borrow(); + + for (idx, arg) in args.iter().enumerate() { + // Don't adjust the span if we already have a more precise span + // within one of the args. + if arg.span.contains(error.obligation.cause.span) { + let references_arg = + typeck_results.expr_ty_opt(arg).map_or(false, &ty_matches_self) + || expected_tys.get(idx).copied().map_or(false, &ty_matches_self); + if references_arg && !arg.span.from_expansion() { + error.obligation.cause.map_code(|parent_code| { + ObligationCauseCode::FunctionArgumentObligation { + arg_hir_id: args[idx].hir_id, + call_hir_id: expr.hir_id, + parent_code, + } + }) + } + continue 'outer; + } + } // Collect the argument position for all arguments that could have caused this // `FulfillmentError`. - let typeck_results = self.typeck_results.borrow(); let mut referenced_in: Vec<_> = std::iter::zip(expected_tys, args) .enumerate() .flat_map(|(idx, (expected_ty, arg))| { @@ -1688,7 +1710,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.resolve_vars_if_possible(ty); // We walk the argument type because the argument's type could have // been `Option`, but the `FulfillmentError` references `T`. - if ty.walk().any(|arg| arg == self_) { Some(i) } else { None } + if ty_matches_self(ty) { Some(i) } else { None } }) .collect(); @@ -1699,18 +1721,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { referenced_in.sort_unstable(); referenced_in.dedup(); - if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { + if let &[idx] = &referenced_in[..] { // Do not point at the inside of a macro. // That would often result in poor error messages. - if args[ref_in].span.from_expansion() { - return; + if args[idx].span.from_expansion() { + continue; } // We make sure that only *one* argument matches the obligation failure // and we assign the obligation's span to its expression's. - error.obligation.cause.span = args[ref_in].span; + error.obligation.cause.span = args[idx].span; error.obligation.cause.map_code(|parent_code| { ObligationCauseCode::FunctionArgumentObligation { - arg_hir_id: args[ref_in].hir_id, + arg_hir_id: args[idx].hir_id, call_hir_id: expr.hir_id, parent_code, } diff --git a/src/test/ui/proc-macro/signature.stderr b/src/test/ui/proc-macro/signature.stderr index 78b0beff0da..a6bd98ddb19 100644 --- a/src/test/ui/proc-macro/signature.stderr +++ b/src/test/ui/proc-macro/signature.stderr @@ -5,10 +5,7 @@ LL | / pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { LL | | LL | | loop {} LL | | } - | | ^ - | | | - | |_call the function in a closure: `|| unsafe { /* code */ }` - | required by a bound introduced by this call + | |_^ call the function in a closure: `|| unsafe { /* code */ }` | = help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for `unsafe extern "C" fn(i32, u32) -> u32 {foo}` = note: unsafe function cannot be called generically without an unsafe block diff --git a/src/test/ui/unsized/unsized-fn-param.stderr b/src/test/ui/unsized/unsized-fn-param.stderr index 3eecca0fa09..edf0b895965 100644 --- a/src/test/ui/unsized/unsized-fn-param.stderr +++ b/src/test/ui/unsized/unsized-fn-param.stderr @@ -2,7 +2,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t --> $DIR/unsized-fn-param.rs:11:11 | LL | foo11("bar", &"baz"); - | ^^^^^ doesn't have a size known at compile-time + | ----- ^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn AsRef` @@ -15,7 +17,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t --> $DIR/unsized-fn-param.rs:13:19 | LL | foo12(&"bar", "baz"); - | ^^^^^ doesn't have a size known at compile-time + | ----- ^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn AsRef` @@ -28,7 +32,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t --> $DIR/unsized-fn-param.rs:16:11 | LL | foo21("bar", &"baz"); - | ^^^^^ doesn't have a size known at compile-time + | ----- ^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn AsRef` @@ -41,7 +47,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t --> $DIR/unsized-fn-param.rs:18:19 | LL | foo22(&"bar", "baz"); - | ^^^^^ doesn't have a size known at compile-time + | ----- ^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn AsRef` diff --git a/src/test/ui/unsized/unsized3.rs b/src/test/ui/unsized/unsized3.rs index 39b6583bc4e..af76aca2c29 100644 --- a/src/test/ui/unsized/unsized3.rs +++ b/src/test/ui/unsized/unsized3.rs @@ -44,6 +44,7 @@ fn f9(x1: Box>) { fn f10(x1: Box>) { f5(&(32, *x1)); //~^ ERROR the size for values of type + //~| ERROR the size for values of type } pub fn main() {} diff --git a/src/test/ui/unsized/unsized3.stderr b/src/test/ui/unsized/unsized3.stderr index 65bdc4c2ea3..d64091b15eb 100644 --- a/src/test/ui/unsized/unsized3.stderr +++ b/src/test/ui/unsized/unsized3.stderr @@ -101,12 +101,12 @@ LL + fn f9(x1: Box>) { | error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized3.rs:45:8 + --> $DIR/unsized3.rs:45:9 | LL | fn f10(x1: Box>) { | - this type parameter needs to be `std::marker::Sized` LL | f5(&(32, *x1)); - | -- ^^^^^^^^^^ doesn't have a size known at compile-time + | -- ^^^^^^^^^ doesn't have a size known at compile-time | | | required by a bound introduced by this call | @@ -123,6 +123,37 @@ LL - fn f10(x1: Box>) { LL + fn f10(x1: Box>) { | -error: aborting due to 5 previous errors +error[E0277]: the size for values of type `X` cannot be known at compilation time + --> $DIR/unsized3.rs:45:8 + | +LL | fn f10(x1: Box>) { + | - this type parameter needs to be `std::marker::Sized` +LL | f5(&(32, *x1)); + | -- ^^^^^^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | +note: required because it appears within the type `S` + --> $DIR/unsized3.rs:28:8 + | +LL | struct S { + | ^ + = note: required because it appears within the type `({integer}, S)` +note: required by a bound in `f5` + --> $DIR/unsized3.rs:24:7 + | +LL | fn f5(x: &Y) {} + | ^ required by this bound in `f5` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn f10(x1: Box>) { +LL + fn f10(x1: Box>) { + | +help: consider relaxing the implicit `Sized` restriction + | +LL | fn f5(x: &Y) {} + | ++++++++ + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`.