Skip to content
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

Elaborate Future::Output when printing opaque impl Future type #91021

Merged
merged 1 commit into from
Nov 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 55 additions & 11 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -649,30 +649,74 @@ pub trait PrettyPrinter<'tcx>:

let mut first = true;
let mut is_sized = false;
let mut is_future = false;
let mut future_output_ty = None;

p!("impl");
for (predicate, _) in bounds {
let predicate = predicate.subst(self.tcx(), substs);
let bound_predicate = predicate.kind();
if let ty::PredicateKind::Trait(pred) = bound_predicate.skip_binder() {
let trait_ref = bound_predicate.rebind(pred.trait_ref);
// Don't print +Sized, but rather +?Sized if absent.
if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() {
is_sized = true;
continue;

match bound_predicate.skip_binder() {
ty::PredicateKind::Projection(projection_predicate) => {
let Some(future_trait) = self.tcx().lang_items().future_trait() else { continue };
let future_output_def_id =
self.tcx().associated_item_def_ids(future_trait)[0];

if projection_predicate.projection_ty.item_def_id
== future_output_def_id
{
// We don't account for multiple `Future::Output = Ty` contraints.
is_future = true;
future_output_ty = Some(projection_predicate.ty);
}
Comment on lines +661 to +672
Copy link
Member Author

Choose a reason for hiding this comment

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

A note: copied most of this from get_impl_future_output_ty in rustc_infer::infer::error_reporting. Didn't know how to factor those two together when we're already iterating thru the predicates here, so pardon the code duplication.

}
ty::PredicateKind::Trait(pred) => {
let trait_ref = bound_predicate.rebind(pred.trait_ref);
// Don't print +Sized, but rather +?Sized if absent.
if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait()
{
is_sized = true;
continue;
}

p!(
write("{}", if first { " " } else { "+" }),
print(trait_ref.print_only_trait_path())
);
first = false;
if Some(trait_ref.def_id())
== self.tcx().lang_items().future_trait()
{
is_future = true;
continue;
}

p!(
write("{}", if first { " " } else { "+" }),
print(trait_ref.print_only_trait_path())
);

first = false;
}
_ => {}
}
}

if is_future {
p!(write("{}Future", if first { " " } else { "+" }));
first = false;

if let Some(future_output_ty) = future_output_ty {
// Don't print projection types, which we (unfortunately) see often
// in the error outputs involving async blocks.
if !matches!(future_output_ty.kind(), ty::Projection(_)) {
p!("<Output = ", print(future_output_ty), ">");
}
}
}

if !is_sized {
p!(write("{}?Sized", if first { " " } else { "+" }));
} else if first {
p!(" Sized");
}

Ok(self)
});
}
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/async-await/async-fn-nonsend.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
LL | assert_send(local_dropped_before_await());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-fn-nonsend.rs:24:5
|
Expand All @@ -27,7 +27,7 @@ error: future cannot be sent between threads safely
LL | assert_send(non_send_temporary_in_match());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-fn-nonsend.rs:33:20
|
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/async-await/dont-suggest-missing-await.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ note: while checking the return type of the `async fn`
LL | async fn make_u32() -> u32 {
| ^^^ checked the `Output` of this `async fn`, found opaque type
= note: expected type `u32`
found opaque type `impl Future`
found opaque type `impl Future<Output = u32>`
help: consider `await`ing on the `Future`
|
LL | take_u32(x.await)
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/async-await/generator-desc.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ note: while checking the return type of the `async fn`
|
LL | async fn two() {}
| ^ checked the `Output` of this `async fn`, found opaque type
= note: expected opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:5:16>)
found opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:6:16>)
= note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:5:16>)
found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:6:16>)
= help: consider `await`ing on both `Future`s
= note: distinct uses of `impl Trait` result in different opaque types

Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/async-await/issue-61076.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ async fn foo() -> Result<(), ()> {

async fn bar() -> Result<(), ()> {
foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try`
//~^ NOTE the `?` operator cannot be applied to type `impl Future`
//~| HELP the trait `Try` is not implemented for `impl Future`
//~^ NOTE the `?` operator cannot be applied to type `impl Future<Output = Result<(), ()>>`
//~| HELP the trait `Try` is not implemented for `impl Future<Output = Result<(), ()>>`
//~| NOTE required by `branch`
//~| HELP consider `await`ing on the `Future`
//~| NOTE in this expansion of desugaring of operator `?`
Expand Down Expand Up @@ -84,7 +84,7 @@ async fn baz() -> Result<(), ()> {
//~| NOTE field not available in `impl Future`

struct_().method(); //~ ERROR no method named
//~^ NOTE method not found in `impl Future`
//~^ NOTE method not found in `impl Future<Output = Struct>`
//~| HELP consider `await`ing on the `Future`
Ok(())
}
Expand All @@ -93,7 +93,7 @@ async fn match_() {
match tuple() { //~ HELP consider `await`ing on the `Future`
Tuple(_) => {} //~ ERROR mismatched types
//~^ NOTE expected opaque type, found struct `Tuple`
//~| NOTE expected opaque type `impl Future`
//~| NOTE expected opaque type `impl Future<Output = Tuple>`
}
}

Expand Down
14 changes: 7 additions & 7 deletions src/test/ui/async-await/issue-61076.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try
--> $DIR/issue-61076.rs:42:5
|
LL | foo()?;
| ^^^^^^ the `?` operator cannot be applied to type `impl Future`
| ^^^^^^ the `?` operator cannot be applied to type `impl Future<Output = Result<(), ()>>`
|
= help: the trait `Try` is not implemented for `impl Future`
= help: the trait `Try` is not implemented for `impl Future<Output = Result<(), ()>>`
note: required by `branch`
--> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL
|
Expand Down Expand Up @@ -32,7 +32,7 @@ help: consider `await`ing on the `Future`
LL | t.await?;
| ++++++

error[E0609]: no field `0` on type `impl Future`
error[E0609]: no field `0` on type `impl Future<Output = Tuple>`
--> $DIR/issue-61076.rs:78:26
|
LL | let _: i32 = tuple().0;
Expand All @@ -43,7 +43,7 @@ help: consider `await`ing on the `Future` and access the field of its `Output`
LL | let _: i32 = tuple().await.0;
| ++++++

error[E0609]: no field `a` on type `impl Future`
error[E0609]: no field `a` on type `impl Future<Output = Struct>`
--> $DIR/issue-61076.rs:82:28
|
LL | let _: i32 = struct_().a;
Expand All @@ -54,11 +54,11 @@ help: consider `await`ing on the `Future` and access the field of its `Output`
LL | let _: i32 = struct_().await.a;
| ++++++

error[E0599]: no method named `method` found for opaque type `impl Future` in the current scope
error[E0599]: no method named `method` found for opaque type `impl Future<Output = Struct>` in the current scope
--> $DIR/issue-61076.rs:86:15
|
LL | struct_().method();
| ^^^^^^ method not found in `impl Future`
| ^^^^^^ method not found in `impl Future<Output = Struct>`
|
help: consider `await`ing on the `Future` and calling the method on its `Output`
|
Expand All @@ -76,7 +76,7 @@ note: while checking the return type of the `async fn`
|
LL | async fn tuple() -> Tuple {
| ^^^^^ checked the `Output` of this `async fn`, expected opaque type
= note: expected opaque type `impl Future`
= note: expected opaque type `impl Future<Output = Tuple>`
found struct `Tuple`
help: consider `await`ing on the `Future`
|
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/async-await/issue-64130-1-sync.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: future cannot be shared between threads safely
LL | is_sync(bar());
| ^^^^^ future returned by `bar` is not `Sync`
|
= help: within `impl Future`, the trait `Sync` is not implemented for `Foo`
= help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo`
note: future is not `Sync` as this value is used across an await
--> $DIR/issue-64130-1-sync.rs:15:5
|
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/async-await/issue-64130-2-send.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
LL | is_send(bar());
| ^^^^^ future returned by `bar` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `Foo`
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Foo`
note: future is not `Send` as this value is used across an await
--> $DIR/issue-64130-2-send.rs:15:5
|
Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/async-await/issue-64130-3-other.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@
// This tests the the unspecialized async-await-specific error when futures don't implement an
// auto trait (which is not Send or Sync) due to some type that was captured.

auto trait Qux { }
auto trait Qux {}

struct Foo;

impl !Qux for Foo {}

fn is_qux<T: Qux>(t: T) { }
fn is_qux<T: Qux>(t: T) {}

async fn bar() {
let x = Foo;
baz().await;
}

async fn baz() { }
async fn baz() {}

fn main() {
is_qux(bar());
//~^ ERROR the trait bound `Foo: Qux` is not satisfied in `impl Future`
//~^ ERROR the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>`
}
8 changes: 4 additions & 4 deletions src/test/ui/async-await/issue-64130-3-other.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future`
error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>`
--> $DIR/issue-64130-3-other.rs:24:12
|
LL | async fn bar() {
| - within this `impl Future`
| - within this `impl Future<Output = ()>`
...
LL | is_qux(bar());
| ^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo`
| ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo`
|
note: future does not implement `Qux` as this value is used across an await
--> $DIR/issue-64130-3-other.rs:18:5
Expand All @@ -19,7 +19,7 @@ LL | }
note: required by a bound in `is_qux`
--> $DIR/issue-64130-3-other.rs:14:14
|
LL | fn is_qux<T: Qux>(t: T) { }
LL | fn is_qux<T: Qux>(t: T) {}
| ^^^ required by this bound in `is_qux`

error: aborting due to previous error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
LL | is_send(foo());
| ^^^^^ future returned by `foo` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`
note: future is not `Send` as this value is used across an await
--> $DIR/issue-64130-non-send-future-diags.rs:17:5
|
Expand Down
10 changes: 5 additions & 5 deletions src/test/ui/async-await/issue-68112.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ note: future is not `Send` as it awaits another future which is not `Send`
--> $DIR/issue-68112.rs:31:17
|
LL | let _ = non_send_fut.await;
| ^^^^^^^^^^^^ await occurs here on type `impl Future`, which is not `Send`
| ^^^^^^^^^^^^ await occurs here on type `impl Future<Output = Arc<RefCell<i32>>>`, which is not `Send`
note: required by a bound in `require_send`
--> $DIR/issue-68112.rs:11:25
|
Expand All @@ -27,7 +27,7 @@ note: future is not `Send` as it awaits another future which is not `Send`
--> $DIR/issue-68112.rs:40:17
|
LL | let _ = make_non_send_future1().await;
| ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl Future`, which is not `Send`
| ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl Future<Output = Arc<RefCell<i32>>>`, which is not `Send`
note: required by a bound in `require_send`
--> $DIR/issue-68112.rs:11:25
|
Expand All @@ -45,9 +45,9 @@ LL | require_send(send_fut);
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `{ResumeTy, impl Future, (), i32, Ready<i32>}`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `{ResumeTy, impl Future<Output = Arc<RefCell<i32>>>, (), i32, Ready<i32>}`
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>`
= note: required because it appears within the type `impl Future`
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/async-await/issue-71137.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
LL | fake_spawn(wrong_mutex());
| ^^^^^^^^^^^^^ future returned by `wrong_mutex` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`
note: future is not `Send` as this value is used across an await
--> $DIR/issue-71137.rs:14:5
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: lifetime may not live long enough
LL | let _ = foo(|x| bar(x));
| -- ^^^^^^ returning this value requires that `'1` must outlive `'2`
| ||
| |return type of closure `impl Future` contains a lifetime `'2`
| |return type of closure `impl Future<Output = ()>` contains a lifetime `'2`
| has type `&'1 u8`

error: aborting due to previous error
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/async-await/issue-84841.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try
--> $DIR/issue-84841.rs:9:5
|
LL | test()?;
| ^^^^^^^ the `?` operator cannot be applied to type `impl Future`
| ^^^^^^^ the `?` operator cannot be applied to type `impl Future<Output = ()>`
|
= help: the trait `Try` is not implemented for `impl Future`
= help: the trait `Try` is not implemented for `impl Future<Output = ()>`
note: required by `branch`
--> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL
|
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/async-await/issues/issue-67893.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: generator cannot be sent between threads safely
LL | g(issue_67893::run())
| ^^^^^^^^^^^^^^^^^^ generator is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
note: required by a bound in `g`
--> $DIR/issue-67893.rs:6:14
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ note: while checking the return type of the `async fn`
LL | async fn make_u32() -> u32 {
| ^^^ checked the `Output` of this `async fn`, found opaque type
= note: expected type `u32`
found opaque type `impl Future`
found opaque type `impl Future<Output = u32>`
help: consider `await`ing on the `Future`
|
LL | take_u32(x.await)
Expand Down
Loading