Skip to content

Commit 3379721

Browse files
authored
Rollup merge of #91021 - compiler-errors:print_future_output, r=estebank
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 = `?
2 parents 59c9c66 + f6392a1 commit 3379721

27 files changed

+119
-75
lines changed

compiler/rustc_middle/src/ty/print/pretty.rs

+55-11
Original file line numberDiff line numberDiff line change
@@ -649,30 +649,74 @@ pub trait PrettyPrinter<'tcx>:
649649

650650
let mut first = true;
651651
let mut is_sized = false;
652+
let mut is_future = false;
653+
let mut future_output_ty = None;
654+
652655
p!("impl");
653656
for (predicate, _) in bounds {
654657
let predicate = predicate.subst(self.tcx(), substs);
655658
let bound_predicate = predicate.kind();
656-
if let ty::PredicateKind::Trait(pred) = bound_predicate.skip_binder() {
657-
let trait_ref = bound_predicate.rebind(pred.trait_ref);
658-
// Don't print +Sized, but rather +?Sized if absent.
659-
if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() {
660-
is_sized = true;
661-
continue;
659+
660+
match bound_predicate.skip_binder() {
661+
ty::PredicateKind::Projection(projection_predicate) => {
662+
let Some(future_trait) = self.tcx().lang_items().future_trait() else { continue };
663+
let future_output_def_id =
664+
self.tcx().associated_item_def_ids(future_trait)[0];
665+
666+
if projection_predicate.projection_ty.item_def_id
667+
== future_output_def_id
668+
{
669+
// We don't account for multiple `Future::Output = Ty` contraints.
670+
is_future = true;
671+
future_output_ty = Some(projection_predicate.ty);
672+
}
662673
}
674+
ty::PredicateKind::Trait(pred) => {
675+
let trait_ref = bound_predicate.rebind(pred.trait_ref);
676+
// Don't print +Sized, but rather +?Sized if absent.
677+
if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait()
678+
{
679+
is_sized = true;
680+
continue;
681+
}
663682

664-
p!(
665-
write("{}", if first { " " } else { "+" }),
666-
print(trait_ref.print_only_trait_path())
667-
);
668-
first = false;
683+
if Some(trait_ref.def_id())
684+
== self.tcx().lang_items().future_trait()
685+
{
686+
is_future = true;
687+
continue;
688+
}
689+
690+
p!(
691+
write("{}", if first { " " } else { "+" }),
692+
print(trait_ref.print_only_trait_path())
693+
);
694+
695+
first = false;
696+
}
697+
_ => {}
669698
}
670699
}
700+
701+
if is_future {
702+
p!(write("{}Future", if first { " " } else { "+" }));
703+
first = false;
704+
705+
if let Some(future_output_ty) = future_output_ty {
706+
// Don't print projection types, which we (unfortunately) see often
707+
// in the error outputs involving async blocks.
708+
if !matches!(future_output_ty.kind(), ty::Projection(_)) {
709+
p!("<Output = ", print(future_output_ty), ">");
710+
}
711+
}
712+
}
713+
671714
if !is_sized {
672715
p!(write("{}?Sized", if first { " " } else { "+" }));
673716
} else if first {
674717
p!(" Sized");
675718
}
719+
676720
Ok(self)
677721
});
678722
}

src/test/ui/async-await/async-fn-nonsend.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
44
LL | assert_send(local_dropped_before_await());
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
66
|
7-
= help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`
7+
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
88
note: future is not `Send` as this value is used across an await
99
--> $DIR/async-fn-nonsend.rs:24:5
1010
|
@@ -27,7 +27,7 @@ error: future cannot be sent between threads safely
2727
LL | assert_send(non_send_temporary_in_match());
2828
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
2929
|
30-
= help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`
30+
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
3131
note: future is not `Send` as this value is used across an await
3232
--> $DIR/async-fn-nonsend.rs:33:20
3333
|

src/test/ui/async-await/dont-suggest-missing-await.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ note: while checking the return type of the `async fn`
1010
LL | async fn make_u32() -> u32 {
1111
| ^^^ checked the `Output` of this `async fn`, found opaque type
1212
= note: expected type `u32`
13-
found opaque type `impl Future`
13+
found opaque type `impl Future<Output = u32>`
1414
help: consider `await`ing on the `Future`
1515
|
1616
LL | take_u32(x.await)

src/test/ui/async-await/generator-desc.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ note: while checking the return type of the `async fn`
2525
|
2626
LL | async fn two() {}
2727
| ^ checked the `Output` of this `async fn`, found opaque type
28-
= note: expected opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:5:16>)
29-
found opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:6:16>)
28+
= note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:5:16>)
29+
found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:6:16>)
3030
= help: consider `await`ing on both `Future`s
3131
= note: distinct uses of `impl Trait` result in different opaque types
3232

src/test/ui/async-await/issue-61076.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ async fn foo() -> Result<(), ()> {
4040

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

8686
struct_().method(); //~ ERROR no method named
87-
//~^ NOTE method not found in `impl Future`
87+
//~^ NOTE method not found in `impl Future<Output = Struct>`
8888
//~| HELP consider `await`ing on the `Future`
8989
Ok(())
9090
}
@@ -93,7 +93,7 @@ async fn match_() {
9393
match tuple() { //~ HELP consider `await`ing on the `Future`
9494
Tuple(_) => {} //~ ERROR mismatched types
9595
//~^ NOTE expected opaque type, found struct `Tuple`
96-
//~| NOTE expected opaque type `impl Future`
96+
//~| NOTE expected opaque type `impl Future<Output = Tuple>`
9797
}
9898
}
9999

src/test/ui/async-await/issue-61076.stderr

+7-7
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try
22
--> $DIR/issue-61076.rs:42:5
33
|
44
LL | foo()?;
5-
| ^^^^^^ the `?` operator cannot be applied to type `impl Future`
5+
| ^^^^^^ the `?` operator cannot be applied to type `impl Future<Output = Result<(), ()>>`
66
|
7-
= help: the trait `Try` is not implemented for `impl Future`
7+
= help: the trait `Try` is not implemented for `impl Future<Output = Result<(), ()>>`
88
note: required by `branch`
99
--> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL
1010
|
@@ -32,7 +32,7 @@ help: consider `await`ing on the `Future`
3232
LL | t.await?;
3333
| ++++++
3434

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

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

57-
error[E0599]: no method named `method` found for opaque type `impl Future` in the current scope
57+
error[E0599]: no method named `method` found for opaque type `impl Future<Output = Struct>` in the current scope
5858
--> $DIR/issue-61076.rs:86:15
5959
|
6060
LL | struct_().method();
61-
| ^^^^^^ method not found in `impl Future`
61+
| ^^^^^^ method not found in `impl Future<Output = Struct>`
6262
|
6363
help: consider `await`ing on the `Future` and calling the method on its `Output`
6464
|
@@ -76,7 +76,7 @@ note: while checking the return type of the `async fn`
7676
|
7777
LL | async fn tuple() -> Tuple {
7878
| ^^^^^ checked the `Output` of this `async fn`, expected opaque type
79-
= note: expected opaque type `impl Future`
79+
= note: expected opaque type `impl Future<Output = Tuple>`
8080
found struct `Tuple`
8181
help: consider `await`ing on the `Future`
8282
|

src/test/ui/async-await/issue-64130-1-sync.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: future cannot be shared between threads safely
44
LL | is_sync(bar());
55
| ^^^^^ future returned by `bar` is not `Sync`
66
|
7-
= help: within `impl Future`, the trait `Sync` is not implemented for `Foo`
7+
= help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo`
88
note: future is not `Sync` as this value is used across an await
99
--> $DIR/issue-64130-1-sync.rs:15:5
1010
|

src/test/ui/async-await/issue-64130-2-send.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
44
LL | is_send(bar());
55
| ^^^^^ future returned by `bar` is not `Send`
66
|
7-
= help: within `impl Future`, the trait `Send` is not implemented for `Foo`
7+
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Foo`
88
note: future is not `Send` as this value is used across an await
99
--> $DIR/issue-64130-2-send.rs:15:5
1010
|

src/test/ui/async-await/issue-64130-3-other.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@
55
// This tests the the unspecialized async-await-specific error when futures don't implement an
66
// auto trait (which is not Send or Sync) due to some type that was captured.
77

8-
auto trait Qux { }
8+
auto trait Qux {}
99

1010
struct Foo;
1111

1212
impl !Qux for Foo {}
1313

14-
fn is_qux<T: Qux>(t: T) { }
14+
fn is_qux<T: Qux>(t: T) {}
1515

1616
async fn bar() {
1717
let x = Foo;
1818
baz().await;
1919
}
2020

21-
async fn baz() { }
21+
async fn baz() {}
2222

2323
fn main() {
2424
is_qux(bar());
25-
//~^ ERROR the trait bound `Foo: Qux` is not satisfied in `impl Future`
25+
//~^ ERROR the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>`
2626
}

src/test/ui/async-await/issue-64130-3-other.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future`
1+
error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>`
22
--> $DIR/issue-64130-3-other.rs:24:12
33
|
44
LL | async fn bar() {
5-
| - within this `impl Future`
5+
| - within this `impl Future<Output = ()>`
66
...
77
LL | is_qux(bar());
8-
| ^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo`
8+
| ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo`
99
|
1010
note: future does not implement `Qux` as this value is used across an await
1111
--> $DIR/issue-64130-3-other.rs:18:5
@@ -19,7 +19,7 @@ LL | }
1919
note: required by a bound in `is_qux`
2020
--> $DIR/issue-64130-3-other.rs:14:14
2121
|
22-
LL | fn is_qux<T: Qux>(t: T) { }
22+
LL | fn is_qux<T: Qux>(t: T) {}
2323
| ^^^ required by this bound in `is_qux`
2424

2525
error: aborting due to previous error

src/test/ui/async-await/issue-64130-non-send-future-diags.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
44
LL | is_send(foo());
55
| ^^^^^ future returned by `foo` is not `Send`
66
|
7-
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`
7+
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`
88
note: future is not `Send` as this value is used across an await
99
--> $DIR/issue-64130-non-send-future-diags.rs:17:5
1010
|

src/test/ui/async-await/issue-68112.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ note: future is not `Send` as it awaits another future which is not `Send`
99
--> $DIR/issue-68112.rs:31:17
1010
|
1111
LL | let _ = non_send_fut.await;
12-
| ^^^^^^^^^^^^ await occurs here on type `impl Future`, which is not `Send`
12+
| ^^^^^^^^^^^^ await occurs here on type `impl Future<Output = Arc<RefCell<i32>>>`, which is not `Send`
1313
note: required by a bound in `require_send`
1414
--> $DIR/issue-68112.rs:11:25
1515
|
@@ -27,7 +27,7 @@ note: future is not `Send` as it awaits another future which is not `Send`
2727
--> $DIR/issue-68112.rs:40:17
2828
|
2929
LL | let _ = make_non_send_future1().await;
30-
| ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl Future`, which is not `Send`
30+
| ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl Future<Output = Arc<RefCell<i32>>>`, which is not `Send`
3131
note: required by a bound in `require_send`
3232
--> $DIR/issue-68112.rs:11:25
3333
|
@@ -45,9 +45,9 @@ LL | require_send(send_fut);
4545
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]`
4646
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>`
4747
= note: required because it appears within the type `impl Future`
48-
= note: required because it appears within the type `impl Future`
49-
= note: required because it appears within the type `impl Future`
50-
= note: required because it appears within the type `{ResumeTy, impl Future, (), i32, Ready<i32>}`
48+
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
49+
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
50+
= note: required because it appears within the type `{ResumeTy, impl Future<Output = Arc<RefCell<i32>>>, (), i32, Ready<i32>}`
5151
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]`
5252
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>`
5353
= note: required because it appears within the type `impl Future`

src/test/ui/async-await/issue-71137.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
44
LL | fake_spawn(wrong_mutex());
55
| ^^^^^^^^^^^^^ future returned by `wrong_mutex` is not `Send`
66
|
7-
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`
7+
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`
88
note: future is not `Send` as this value is used across an await
99
--> $DIR/issue-71137.rs:14:5
1010
|

src/test/ui/async-await/issue-74497-lifetime-in-opaque.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: lifetime may not live long enough
44
LL | let _ = foo(|x| bar(x));
55
| -- ^^^^^^ returning this value requires that `'1` must outlive `'2`
66
| ||
7-
| |return type of closure `impl Future` contains a lifetime `'2`
7+
| |return type of closure `impl Future<Output = ()>` contains a lifetime `'2`
88
| has type `&'1 u8`
99

1010
error: aborting due to previous error

src/test/ui/async-await/issue-84841.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try
22
--> $DIR/issue-84841.rs:9:5
33
|
44
LL | test()?;
5-
| ^^^^^^^ the `?` operator cannot be applied to type `impl Future`
5+
| ^^^^^^^ the `?` operator cannot be applied to type `impl Future<Output = ()>`
66
|
7-
= help: the trait `Try` is not implemented for `impl Future`
7+
= help: the trait `Try` is not implemented for `impl Future<Output = ()>`
88
note: required by `branch`
99
--> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL
1010
|

src/test/ui/async-await/issues/issue-67893.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: generator cannot be sent between threads safely
44
LL | g(issue_67893::run())
55
| ^^^^^^^^^^^^^^^^^^ generator is not `Send`
66
|
7-
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
7+
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
88
note: required by a bound in `g`
99
--> $DIR/issue-67893.rs:6:14
1010
|

src/test/ui/async-await/suggest-missing-await-closure.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ note: while checking the return type of the `async fn`
1010
LL | async fn make_u32() -> u32 {
1111
| ^^^ checked the `Output` of this `async fn`, found opaque type
1212
= note: expected type `u32`
13-
found opaque type `impl Future`
13+
found opaque type `impl Future<Output = u32>`
1414
help: consider `await`ing on the `Future`
1515
|
1616
LL | take_u32(x.await)

0 commit comments

Comments
 (0)