Skip to content

Commit

Permalink
Point at argument instead of call for their obligations
Browse files Browse the repository at this point in the history
When an obligation is introduced by a specific `fn` argument, point at
the argument instead of the `fn` call if the obligation fails to be
fulfilled.
  • Loading branch information
estebank committed Sep 16, 2021
1 parent 2b5ddf3 commit 284a8a9
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 50 deletions.
12 changes: 10 additions & 2 deletions compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
Expand Up @@ -83,7 +83,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// version (resolve_vars_if_possible), this version will
/// also select obligations if it seems useful, in an effort
/// to get more type information.
pub(in super::super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
pub(in super::super) fn resolve_vars_with_obligations(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {})
}

pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment(
&self,
mut ty: Ty<'tcx>,
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) -> Ty<'tcx> {
debug!("resolve_vars_with_obligations(ty={:?})", ty);

// No Infer()? Nothing needs doing.
Expand All @@ -103,7 +111,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// possible. This can help substantially when there are
// indirect dependencies that don't seem worth tracking
// precisely.
self.select_obligations_where_possible(false, |_| {});
self.select_obligations_where_possible(false, mutate_fulfillment_errors);
ty = self.resolve_vars_if_possible(ty);

debug!("resolve_vars_with_obligations: ty={:?}", ty);
Expand Down
32 changes: 31 additions & 1 deletion compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
Expand Up @@ -354,8 +354,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
continue;
}

debug!("checking the argument");
let formal_ty = formal_tys[i];
debug!("checking argument {}: {:?} = {:?}", i, arg, formal_ty);

// The special-cased logic below has three functions:
// 1. Provide as good of an expected type as possible.
Expand All @@ -367,6 +367,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// to, which is `expected_ty` if `rvalue_hint` returns an
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);

// Cause selection errors caused by resolving a single argument to point at the
// argument and not the call. This is otherwise redundant with the `demand_coerce`
// call immediately after, but it lets us customize the span pointed to in the
// fulfillment error to be more accurate.
let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment(
coerce_ty,
|errors| {
// This is not coming from a macro or a `derive`.
if sp.desugaring_kind().is_none()
&& !arg.span.from_expansion()
// Do not change the spans of `async fn`s.
&& !matches!(
expr.kind,
hir::ExprKind::Call(
hir::Expr {
kind: hir::ExprKind::Path(hir::QPath::LangItem(_, _)),
..
},
_
)
) {
for error in errors {
error.obligation.cause.make_mut().span = arg.span;
error.points_at_arg_span = true;
}
}
},
);

// We're processing function arguments so we definitely want to use
// two-phase borrows.
self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
Expand Down
12 changes: 6 additions & 6 deletions src/test/ui/associated-types/associated-types-path-2.stderr
Expand Up @@ -10,10 +10,10 @@ LL | f1(2i32, 4u32);
| ~~~

error[E0277]: the trait bound `u32: Foo` is not satisfied
--> $DIR/associated-types-path-2.rs:29:5
--> $DIR/associated-types-path-2.rs:29:14
|
LL | f1(2u32, 4u32);
| ^^ the trait `Foo` is not implemented for `u32`
| ^^^^ the trait `Foo` is not implemented for `u32`
|
note: required by a bound in `f1`
--> $DIR/associated-types-path-2.rs:13:14
Expand All @@ -25,13 +25,13 @@ error[E0277]: the trait bound `u32: Foo` is not satisfied
--> $DIR/associated-types-path-2.rs:29:5
|
LL | f1(2u32, 4u32);
| ^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u32`
| ^^ the trait `Foo` is not implemented for `u32`

error[E0277]: the trait bound `u32: Foo` is not satisfied
--> $DIR/associated-types-path-2.rs:35:5
--> $DIR/associated-types-path-2.rs:35:14
|
LL | f1(2u32, 4i32);
| ^^ the trait `Foo` is not implemented for `u32`
| ^^^^ the trait `Foo` is not implemented for `u32`
|
note: required by a bound in `f1`
--> $DIR/associated-types-path-2.rs:13:14
Expand All @@ -43,7 +43,7 @@ error[E0277]: the trait bound `u32: Foo` is not satisfied
--> $DIR/associated-types-path-2.rs:35:5
|
LL | f1(2u32, 4i32);
| ^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u32`
| ^^ the trait `Foo` is not implemented for `u32`

error[E0308]: mismatched types
--> $DIR/associated-types-path-2.rs:41:18
Expand Down
@@ -1,11 +1,17 @@
error[E0631]: type mismatch in closure arguments
--> $DIR/issue-62529-1.rs:80:10
|
LL | task(annotate(
| ^^^^^^^^ expected signature of `for<'r> fn(<RefMutFamily<usize> as FamilyLt<'r>>::Out) -> _`
...
LL | |value: &mut usize| {
| ------------------- found signature of `for<'r> fn(&'r mut usize) -> _`
LL | task(annotate(
| __________^
LL | |
LL | |
LL | | Annotate::<RefMutFamily<usize>>::new(),
LL | | |value: &mut usize| {
| | ------------------- found signature of `for<'r> fn(&'r mut usize) -> _`
LL | | *value = 2;
LL | | }
LL | | ));
| |_____^ expected signature of `for<'r> fn(<RefMutFamily<usize> as FamilyLt<'r>>::Out) -> _`
|
note: required by a bound in `annotate`
--> $DIR/issue-62529-1.rs:44:8
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-60218.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `&u32: Foo` is not satisfied
--> $DIR/issue-60218.rs:18:5
--> $DIR/issue-60218.rs:18:27
|
LL | trigger_error(vec![], |x: &u32| x)
| ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `&u32`
| ^^^^^^^^^^^ the trait `Foo` is not implemented for `&u32`
|
note: required by a bound in `trigger_error`
--> $DIR/issue-60218.rs:13:72
Expand Down
4 changes: 1 addition & 3 deletions src/test/ui/unsized/unsized3.rs
Expand Up @@ -44,8 +44,6 @@ fn f9<X: ?Sized>(x1: Box<S<X>>) {
fn f10<X: ?Sized>(x1: Box<S<X>>) {
f5(&(32, *x1));
//~^ ERROR the size for values of type
//~| ERROR the size for values of type
}

pub fn main() {
}
pub fn main() {}
33 changes: 2 additions & 31 deletions src/test/ui/unsized/unsized3.stderr
Expand Up @@ -92,27 +92,6 @@ LL - fn f9<X: ?Sized>(x1: Box<S<X>>) {
LL + fn f9<X>(x1: Box<S<X>>) {
|

error[E0277]: the size for values of type `X` cannot be known at compilation time
--> $DIR/unsized3.rs:45:9
|
LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
| - this type parameter needs to be `std::marker::Sized`
LL | f5(&(32, *x1));
| ^^^^^^^^^ doesn't have a size known at compile-time
|
note: required because it appears within the type `S<X>`
--> $DIR/unsized3.rs:28:8
|
LL | struct S<X: ?Sized> {
| ^
= note: required because it appears within the type `({integer}, S<X>)`
= note: tuples must have a statically known size to be initialized
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn f10<X: ?Sized>(x1: Box<S<X>>) {
LL + fn f10<X>(x1: Box<S<X>>) {
|

error[E0277]: the size for values of type `X` cannot be known at compilation time
--> $DIR/unsized3.rs:45:8
|
Expand All @@ -127,21 +106,13 @@ note: required because it appears within the type `S<X>`
LL | struct S<X: ?Sized> {
| ^
= note: required because it appears within the type `({integer}, S<X>)`
note: required by a bound in `f5`
--> $DIR/unsized3.rs:24:7
|
LL | fn f5<Y>(x: &Y) {}
| ^ required by this bound in `f5`
= note: tuples must have a statically known size to be initialized
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn f10<X: ?Sized>(x1: Box<S<X>>) {
LL + fn f10<X>(x1: Box<S<X>>) {
|
help: consider relaxing the implicit `Sized` restriction
|
LL | fn f5<Y: ?Sized>(x: &Y) {}
| ++++++++

error: aborting due to 6 previous errors
error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0277`.

0 comments on commit 284a8a9

Please sign in to comment.