Skip to content

Commit

Permalink
Rollup merge of #91021 - compiler-errors:print_future_output, r=estebank
Browse files Browse the repository at this point in the history
Elaborate `Future::Output` when printing opaque `impl Future` type

I would love to see the `Output =` type when printing type errors involving opaque `impl Future`.

[Test code](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a800b481edd31575fbcaf5771a9c3678)

Before (cut relevant part of output):
```
note: while checking the return type of the `async fn`
 --> /home/michael/test.rs:5:19
  |
5 | async fn bar() -> usize {
  |                   ^^^^^ checked the `Output` of this `async fn`, found opaque type
  = note:     expected type `usize`
          found opaque type `impl Future`
```

After:
```
note: while checking the return type of the `async fn`
 --> /home/michael/test.rs:5:19
  |
5 | async fn bar() -> usize {
  |                   ^^^^^ checked the `Output` of this `async fn`, found opaque type
  = note:     expected type `usize`
          found opaque type `impl Future<Output = usize>`
```

Note the "found opaque type `impl Future<Output = usize>`" in the new output.

----

Questions:
1. We skip printing the output type when it's a projection, since I have been seeing some types like `impl Future<Output = <[static generator@/home/michael/test.rs:2:11: 2:21] as Generator<ResumeTy>>::Return>` which are not particularly helpful and leak implementation detail.
    * Am I able to normalize this type within `rustc_middle::ty::print::pretty`? Alternatively, can we normalize it when creating the diagnostic? Otherwise, I'm fine with skipping it and falling back to the old output.
    * Should I suppress any other types? I didn't encounter anything other than this generator projection type.
2. Not sure what the formatting of this should be. Do I include spaces in `Output = `?
  • Loading branch information
matthiaskrgr committed Nov 20, 2021
2 parents bd46fba + f6392a1 commit 1e446ef
Show file tree
Hide file tree
Showing 27 changed files with 119 additions and 75 deletions.
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);
}
}
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

0 comments on commit 1e446ef

Please sign in to comment.