Skip to content

Commit

Permalink
When possible point at argument causing item obligation failure
Browse files Browse the repository at this point in the history
  • Loading branch information
estebank committed Sep 19, 2019
1 parent 9b9d2af commit 02e3fb8
Show file tree
Hide file tree
Showing 66 changed files with 674 additions and 513 deletions.
40 changes: 36 additions & 4 deletions src/librustc_typeck/check/mod.rs
Expand Up @@ -3253,6 +3253,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
formal_tys.clone()
};

let mut final_arg_types: Vec<(usize, Ty<'_>)> = vec![];

// Check the arguments.
// We do this in a pretty awful way: first we type-check any arguments
// that are not closures, then we type-check the closures. This is so
Expand All @@ -3265,7 +3267,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// an "opportunistic" vtable resolution of any trait bounds on
// the call. This helps coercions.
if check_closures {
self.select_obligations_where_possible(false);
// We don't use `select_obligations_where_possible` to try to figure out if the
// obligation is comming from a single fn call argument, and if it is, we point
// at the expression corresponding to that argument, instead of the call.
if let Err(
mut errors,
) = self.fulfillment_cx.borrow_mut().select_where_possible(self) {
for error in &mut errors {
if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
let mut referenced_in = vec![];
for (i, ty) in &final_arg_types {
let ty = self.resolve_vars_if_possible(ty);
info!("final ty {} {:?}", i, ty);
for ty in ty.walk() {
info!("walk {:?}", ty);
if ty == predicate.skip_binder().self_ty() {
referenced_in.push(*i);
}
}
}
if referenced_in.len() == 1 {
error.obligation.cause.span = args[referenced_in[0]].span;
}
}
}
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
}
}

// For C-variadic functions, we don't have a declared type for all of
Expand Down Expand Up @@ -3311,6 +3338,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We're processing function arguments so we definitely want to use
// two-phase borrows.
self.demand_coerce(&arg, checked_ty, coerce_ty, AllowTwoPhase::Yes);
final_arg_types.push((i, coerce_ty));

// 3. Relate the expected type and the formal one,
// if the expected type was used for the coercion.
Expand Down Expand Up @@ -3514,8 +3542,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

// Check bounds on type arguments used in the path.
let bounds = self.instantiate_bounds(path_span, did, substs);
let cause = traits::ObligationCause::new(path_span, self.body_id,
traits::ItemObligation(did));
let cause = traits::ObligationCause::new(
path_span,
self.body_id,
traits::ItemObligation(did),
);
self.add_obligations_for_parameters(cause, &bounds);

Some((variant, ty))
Expand Down Expand Up @@ -4639,7 +4670,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let bounds = self.instantiate_bounds(span, def_id, &substs);
self.add_obligations_for_parameters(
traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)),
&bounds);
&bounds,
);

// Substitute the values for the type parameters into the type of
// the referenced item.
Expand Down
10 changes: 5 additions & 5 deletions src/librustc_typeck/check/wfcheck.rs
Expand Up @@ -506,7 +506,7 @@ fn check_where_clauses<'tcx, 'fcx>(
});

// Now we build the substituted predicates.
let default_obligations = predicates.predicates.iter().flat_map(|&(pred, _)| {
let default_obligations = predicates.predicates.iter().flat_map(|&(pred, sp)| {
#[derive(Default)]
struct CountParams { params: FxHashSet<u32> }
impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
Expand Down Expand Up @@ -539,9 +539,9 @@ fn check_where_clauses<'tcx, 'fcx>(
// Avoid duplication of predicates that contain no parameters, for example.
None
} else {
Some(substituted_pred)
Some((substituted_pred, sp))
}
}).map(|pred| {
}).map(|(pred, sp)| {
// Convert each of those into an obligation. So if you have
// something like `struct Foo<T: Copy = String>`, we would
// take that predicate `T: Copy`, substitute to `String: Copy`
Expand All @@ -551,8 +551,8 @@ fn check_where_clauses<'tcx, 'fcx>(
// Note the subtle difference from how we handle `predicates`
// below: there, we are not trying to prove those predicates
// to be *true* but merely *well-formed*.
let pred = fcx.normalize_associated_types_in(span, &pred);
let cause = traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def_id));
let pred = fcx.normalize_associated_types_in(sp, &pred);
let cause = traits::ObligationCause::new(sp, fcx.body_id, traits::ItemObligation(def_id));
traits::Obligation::new(cause, fcx.param_env, pred)
});

Expand Down
@@ -1,11 +1,11 @@
error[E0277]: the trait bound `<G as GetToInt>::R: ToInt` is not satisfied
--> $DIR/associated-types-bound-failure.rs:17:5
--> $DIR/associated-types-bound-failure.rs:17:19
|
LL | fn to_int(&self) -> isize;
| -------------------------- required by `ToInt::to_int`
...
LL | ToInt::to_int(&g.get())
| ^^^^^^^^^^^^^ the trait `ToInt` is not implemented for `<G as GetToInt>::R`
| ^^^^^^^^ the trait `ToInt` is not implemented for `<G as GetToInt>::R`
|
= help: consider adding a `where <G as GetToInt>::R: ToInt` bound

Expand Down
Expand Up @@ -14,7 +14,8 @@ async fn foo2() -> Result<(), ()> {
}
async fn foo3() -> Result<(), ()> {
let _ = await bar()?; //~ ERROR incorrect use of `await`
//~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
//~^ ERROR the trait bound `impl std::future::Future: std::ops::Try` is not satisfied
//~| ERROR the trait bound `impl std::future::Future: std::ops::Try` is not satisfied
Ok(())
}
async fn foo21() -> Result<(), ()> {
Expand Down
Expand Up @@ -17,117 +17,117 @@ LL | let _ = await bar()?;
| ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:21:13
--> $DIR/incorrect-syntax-suggestions.rs:22:13
|
LL | let _ = await { bar() };
| ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:25:13
--> $DIR/incorrect-syntax-suggestions.rs:26:13
|
LL | let _ = await(bar());
| ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await`

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:29:13
--> $DIR/incorrect-syntax-suggestions.rs:30:13
|
LL | let _ = await { bar() }?;
| ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:33:14
--> $DIR/incorrect-syntax-suggestions.rs:34:14
|
LL | let _ = (await bar())?;
| ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:37:24
--> $DIR/incorrect-syntax-suggestions.rs:38:24
|
LL | let _ = bar().await();
| ^^ help: `await` is not a method call, remove the parentheses

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:41:24
--> $DIR/incorrect-syntax-suggestions.rs:42:24
|
LL | let _ = bar().await()?;
| ^^ help: `await` is not a method call, remove the parentheses

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:53:13
--> $DIR/incorrect-syntax-suggestions.rs:54:13
|
LL | let _ = await bar();
| ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:58:13
--> $DIR/incorrect-syntax-suggestions.rs:59:13
|
LL | let _ = await? bar();
| ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:63:13
--> $DIR/incorrect-syntax-suggestions.rs:64:13
|
LL | let _ = await bar()?;
| ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:68:14
--> $DIR/incorrect-syntax-suggestions.rs:69:14
|
LL | let _ = (await bar())?;
| ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:73:24
--> $DIR/incorrect-syntax-suggestions.rs:74:24
|
LL | let _ = bar().await();
| ^^ help: `await` is not a method call, remove the parentheses

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:78:24
--> $DIR/incorrect-syntax-suggestions.rs:79:24
|
LL | let _ = bar().await()?;
| ^^ help: `await` is not a method call, remove the parentheses

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:106:13
--> $DIR/incorrect-syntax-suggestions.rs:107:13
|
LL | let _ = await!(bar());
| ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:110:13
--> $DIR/incorrect-syntax-suggestions.rs:111:13
|
LL | let _ = await!(bar())?;
| ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:115:17
--> $DIR/incorrect-syntax-suggestions.rs:116:17
|
LL | let _ = await!(bar())?;
| ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:123:17
--> $DIR/incorrect-syntax-suggestions.rs:124:17
|
LL | let _ = await!(bar())?;
| ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`

error: expected expression, found `=>`
--> $DIR/incorrect-syntax-suggestions.rs:131:25
--> $DIR/incorrect-syntax-suggestions.rs:132:25
|
LL | match await { await => () }
| ----- ^^ expected expression
| |
| while parsing this incorrect await expression

error: incorrect use of `await`
--> $DIR/incorrect-syntax-suggestions.rs:131:11
--> $DIR/incorrect-syntax-suggestions.rs:132:11
|
LL | match await { await => () }
| ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await`

error: expected one of `.`, `?`, `{`, or an operator, found `}`
--> $DIR/incorrect-syntax-suggestions.rs:134:1
--> $DIR/incorrect-syntax-suggestions.rs:135:1
|
LL | match await { await => () }
| ----- - expected one of `.`, `?`, `{`, or an operator here
Expand All @@ -138,110 +138,115 @@ LL | }
| ^ unexpected token

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:53:13
--> $DIR/incorrect-syntax-suggestions.rs:54:13
|
LL | fn foo9() -> Result<(), ()> {
| ---- this is not `async`
LL | let _ = await bar();
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:58:13
--> $DIR/incorrect-syntax-suggestions.rs:59:13
|
LL | fn foo10() -> Result<(), ()> {
| ----- this is not `async`
LL | let _ = await? bar();
| ^^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:63:13
--> $DIR/incorrect-syntax-suggestions.rs:64:13
|
LL | fn foo11() -> Result<(), ()> {
| ----- this is not `async`
LL | let _ = await bar()?;
| ^^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:68:14
--> $DIR/incorrect-syntax-suggestions.rs:69:14
|
LL | fn foo12() -> Result<(), ()> {
| ----- this is not `async`
LL | let _ = (await bar())?;
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:73:13
--> $DIR/incorrect-syntax-suggestions.rs:74:13
|
LL | fn foo13() -> Result<(), ()> {
| ----- this is not `async`
LL | let _ = bar().await();
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:78:13
--> $DIR/incorrect-syntax-suggestions.rs:79:13
|
LL | fn foo14() -> Result<(), ()> {
| ----- this is not `async`
LL | let _ = bar().await()?;
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:83:13
--> $DIR/incorrect-syntax-suggestions.rs:84:13
|
LL | fn foo15() -> Result<(), ()> {
| ----- this is not `async`
LL | let _ = bar().await;
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:87:13
--> $DIR/incorrect-syntax-suggestions.rs:88:13
|
LL | fn foo16() -> Result<(), ()> {
| ----- this is not `async`
LL | let _ = bar().await?;
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:92:17
--> $DIR/incorrect-syntax-suggestions.rs:93:17
|
LL | fn foo() -> Result<(), ()> {
| --- this is not `async`
LL | let _ = bar().await?;
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:99:17
--> $DIR/incorrect-syntax-suggestions.rs:100:17
|
LL | let foo = || {
| -- this is not `async`
LL | let _ = bar().await?;
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:115:17
--> $DIR/incorrect-syntax-suggestions.rs:116:17
|
LL | fn foo() -> Result<(), ()> {
| --- this is not `async`
LL | let _ = await!(bar())?;
| ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:123:17
--> $DIR/incorrect-syntax-suggestions.rs:124:17
|
LL | let foo = || {
| -- this is not `async`
LL | let _ = await!(bar())?;
| ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks

error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
error[E0277]: the trait bound `impl std::future::Future: std::ops::Try` is not satisfied
--> $DIR/incorrect-syntax-suggestions.rs:16:19
|
LL | let _ = await bar()?;
| ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future`
| ^^^^^ the trait `std::ops::Try` is not implemented for `impl std::future::Future`
|
= help: the trait `std::ops::Try` is not implemented for `impl std::future::Future`
= note: required by `std::ops::Try::into_result`

error: aborting due to 35 previous errors
error[E0277]: the trait bound `impl std::future::Future: std::ops::Try` is not satisfied
--> $DIR/incorrect-syntax-suggestions.rs:16:19
|
LL | let _ = await bar()?;
| ^^^^^^ the trait `std::ops::Try` is not implemented for `impl std::future::Future`

error: aborting due to 36 previous errors

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

0 comments on commit 02e3fb8

Please sign in to comment.