10000 When possible point at argument causing item obligation failure by estebank · Pull Request #64498 · rust-lang/rust · GitHub
[go: up one dir, main page]

Skip to content

When possible point at argument causing item obligation failure #64498

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 20, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

8000
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
When possible point at argument causing item obligation failure
  • Loading branch information
estebank committed Sep 19, 2019
commit 02e3fb89a7e0c7944ed8237f5d307322879b6fcc
40 changes: 36 additions & 4 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3253,6 +3253,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
formal_tys.clone()
};

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this is going to regress happy-path compile-time perf? (I don't expect by much but still...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see no way of doing this without collecting the resolved types for the general case (there's a lazy way to do it that would only work with fully resolved types in the arguments).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah sure, just pointing out that there is a cost to this, which may be totally acceptable. :)


// 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(
F438
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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`.
Loading
0