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

Perform autoref/autoderef on .await #111773

Closed

Conversation

Jules-Bertholet
Copy link
Contributor

@Jules-Bertholet Jules-Bertholet commented May 19, 2023

This PR adds support for autoref/autoderef of the receiver of an .await (before calling IntoFuture::into_future()).

This PR is not ready to merge yet—the feature works, but diagnostics are regressed. I would like to get some feedback on my current approach, before investing more effort into it.

Fixes #111546.

@rustbot
Copy link
Collaborator

rustbot commented May 19, 2023

r? @wesleywiser

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 19, 2023
@rust-log-analyzer

This comment has been minimized.

}

impl PathSegmentRes {
pub fn get(&self, lang_items: &LanguageItems) -> Res {
Copy link
Member

Choose a reason for hiding this comment

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

This should just take TyCtxt

Copy link
Member

Choose a reason for hiding this comment

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

Actually no, see my comment below about just using Res::Def by itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TyCtxt is defined in rustc_middle, which rustc_hir doesn't depend on.

compiler/rustc_ast_lowering/src/expr.rs Outdated Show resolved Hide resolved
Comment on lines 850 to 1043
res: hir::PathSegmentRes::LangItem(
hir::def::DefKind::AssocFn,
hir::LangItem::IntoFutureIntoFuture,
),
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need this? Why can't we just use Res::Def by itself?

Suggested change
res: hir::PathSegmentRes::LangItem(
hir::def::DefKind::AssocFn,
hir::LangItem::IntoFutureIntoFuture,
),
res: Res::Def(DefKind::AssocFn, tcx.require_lang_item(hir::LangItem::IntoFutureIntoFuture, Some(span))),

Copy link
Member

Choose a reason for hiding this comment

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

This would only break if, e.g., we had an .await call inside of core itself, which I guess may happen. But this really seems complicated for such a special use case.

Copy link
Contributor Author

@Jules-Bertholet Jules-Bertholet May 19, 2023

Choose a reason for hiding this comment

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

Using Res::def directly was my initial approach, but the compiler would crash when trying to get the lang items. I didn't investigate in detail, but I think lang items just aren't available from tcx at that point in compilation.

Copy link
Member

@compiler-errors compiler-errors May 19, 2023

Choose a reason for hiding this comment

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

Sigh, I forgot that there are calls to await in core.

compiler/rustc_hir_typeck/src/method/probe.rs Outdated Show resolved Hide resolved
@compiler-errors
Copy link
Member

compiler-errors commented May 19, 2023

This is a bit contrived, but introducing autoderef here does mean that inference is slightly affected:

async fn test() {
    let mut x = None;
    loop {
        if let Some(x) = x.as_mut() {
            x.await;
        }
        x = Some(std::future::ready(1u32));
    }
}

Goes from passing to failing. This isn't necessarily a dealbreaker, but it should be kept in mind. We probably need to crater this to understand the impact.

Also, we probably need to discuss whether this is behavior we want. I'll nominate this for wg-async I guess.

@compiler-errors compiler-errors added the I-async-nominated Nominated for discussion during an async working group meeting. label May 19, 2023
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@compiler-errors compiler-errors self-assigned this May 23, 2023
@compiler-errors compiler-errors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 29, 2023
@bors
Copy link
Contributor

bors commented Jun 18, 2023

☔ The latest upstream changes (presumably #112755) made this pull request unmergeable. Please resolve the merge conflicts.

@Dylan-DPC
Copy link
Member

@Jules-Bertholet any updates on this?

@Jules-Bertholet
Copy link
Contributor Author

@Dylan-DPC This is blocked on wg-async coming to a decision on the desired behavior.

@Dylan-DPC Dylan-DPC added S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 13, 2023
@vincenzopalazzo
Copy link
Member

We discuss it in today's triage meeting and my idea that needs to be confirmed by some other of the wg is to discuss this in some open discussion that we are having for this kind of problem

@tmandry
Copy link
Member

tmandry commented Aug 14, 2023

We have a discussion scheduled for this Thursday to go over this question.

pub enum PathSegmentRes {
Res(Res),
LangItem(DefKind, LangItem),
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be simpler to add LangItem variant to Res?

ProbeScope::DefId(self.tcx.lang_items().get(item).expect("missing lang item"))
}
_ => ProbeScope::TraitsInScope,
};
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not really fond of this. What about editing the traits_in_scope map from HIR to ensure that Future is the only trait in scope for that HirId?

// `match <expr>.into_future() { ... }`
let into_future_path = self.arena.alloc(hir::PathSegment {
ident: Ident::new(sym::into_future, self.lower_span(span)),
hir_id: expr_hir_id,
Copy link
Contributor

Choose a reason for hiding this comment

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

This should not reuse expr.hir_id. HirIds must be unique.

@eholk eholk removed the I-async-nominated Nominated for discussion during an async working group meeting. label Aug 28, 2023
@apiraino
Copy link
Contributor

@vincenzopalazzo @tmandry just checking progress: was this issue discussed? Anything to report here? thanks

@Jules-Bertholet
Copy link
Contributor Author

Jules-Bertholet commented Aug 31, 2023

Latest update is here. Next step is for me to improve the implementation.

@rustbot label -S-waiting-on-team +S-waiting-on-author

@apiraino apiraino removed the S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). label Sep 1, 2023
@Dylan-DPC Dylan-DPC added S-blocked Status: Blocked on something else such as an RFC or other implementation work. S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). T-lang Relevant to the language team, which will review and decide on the PR/issue. and removed S-blocked Status: Blocked on something else such as an RFC or other implementation work. labels Oct 27, 2023
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Contributor

bors commented Dec 22, 2023

☔ The latest upstream changes (presumably #118847) made this pull request unmergeable. Please resolve the merge conflicts.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@traviscross
Copy link
Contributor

We discussed this in the async triage meeting today. One thing we wanted to see here that we haven't yet is a full analysis of the crater run. We'd want to see all of the root regressions analyzed in the report. And for each of those, we'd be interested in seeing what the suggested fix or workaround would be.

Would the plan be to target Rust 2024? If so, what would the migration strategy be? And, to confirm, would the plan be to maintain indefinitely the different desugaring in the older editions?

@traviscross traviscross added A-async-await Area: Async & Await AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. WG-async Working group: Async & await labels Mar 25, 2024
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-llvm-17 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
#17 exporting to docker image format
#17 sending tarball 30.0s done
#17 DONE 35.7s
##[endgroup]
Setting extra environment values for docker:  --env ENABLE_GCC_CODEGEN=1 --env GCC_EXEC_PREFIX=/usr/lib/gcc/
[CI_JOB_NAME=x86_64-gnu-llvm-17]
---
sccache: Starting the server...
##[group]Configure the build
configure: processing command line
configure: 
configure: build.configure-args := ['--build=x86_64-unknown-linux-gnu', '--llvm-root=/usr/lib/llvm-17', '--enable-llvm-link-shared', '--set', 'rust.thin-lto-import-instr-limit=10', '--set', 'change-id=99999999', '--enable-verbose-configure', '--enable-sccache', '--disable-manage-submodules', '--enable-locked-deps', '--enable-cargo-native-static', '--set', 'rust.codegen-units-std=1', '--set', 'dist.compression-profile=balanced', '--dist-compression-formats=xz', '--disable-dist-src', '--release-channel=nightly', '--enable-debug-assertions', '--enable-overflow-checks', '--enable-llvm-assertions', '--set', 'rust.verify-llvm-ir', '--set', 'rust.codegen-backends=llvm,cranelift,gcc', '--set', 'llvm.static-libstdcpp', '--enable-new-symbol-mangling']
configure: target.x86_64-unknown-linux-gnu.llvm-config := /usr/lib/llvm-17/bin/llvm-config
configure: llvm.link-shared     := True
configure: rust.thin-lto-import-instr-limit := 10
configure: change-id            := 99999999
---

---- [ui] tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.rs stdout ----
diff of stderr:

- error[E0277]: `[usize; usize::MAX]` is not a future
+ error[E0599]: `[usize; usize::MAX]` is not a future
3    |
3    |
4 LL |     [0usize; 0xffff_ffff_ffff_ffff].await;
-    |                                    -^^^^^
-    |                                    ||
-    |                                    ||
-    |                                    |`[usize; usize::MAX]` is not a future
-    |                                    help: remove the `.await`
+    |                                     ^^^^^ `[usize; usize::MAX]` is not a future
9    |
-    = help: the trait `Future` is not implemented for `[usize; usize::MAX]`, which is required by `[usize; usize::MAX]: IntoFuture`
-    = note: [usize; usize::MAX] must be a future or must implement `IntoFuture` to be awaited
-    = note: required for `[usize; usize::MAX]` to implement `IntoFuture`
+    = note: the following trait bounds were not satisfied:
+            `[usize; usize::MAX]: Future`
+            which is required by `[usize; usize::MAX]: IntoFuture`
+            `&[usize; usize::MAX]: Future`
+            which is required by `&[usize; usize::MAX]: IntoFuture`
+            `&mut [usize; usize::MAX]: Future`
+            which is required by `&mut [usize; usize::MAX]: IntoFuture`
+            `&[usize]: Future`
+            which is required by `&[usize]: IntoFuture`
+            `&mut [usize]: Future`
+            which is required by `&mut [usize]: IntoFuture`
14 error[E0752]: `main` function is not allowed to be `async`
15   --> $DIR/debug-ice-attempted-to-add-with-overflow.rs:6:1

19 
---
status: exit status: 1
command: RUSTC_ICE="0" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/async-await/debug-ice-attempted-to-add-with-overflow" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/async-await/debug-ice-attempted-to-add-with-overflow/auxiliary" "--edition=2021"
stdout: none
--- stderr -------------------------------
error[E0599]: `[usize; usize::MAX]` is not a future
   |
   |
LL |     [0usize; 0xffff_ffff_ffff_ffff].await;
   |                                     ^^^^^ `[usize; usize::MAX]` is not a future
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `[usize; usize::MAX]: Future`
           which is required by `[usize; usize::MAX]: IntoFuture`
           `&[usize; usize::MAX]: Future`
           which is required by `&[usize; usize::MAX]: IntoFuture`
           `&mut [usize; usize::MAX]: Future`
           which is required by `&mut [usize; usize::MAX]: IntoFuture`
           `&[usize]: Future`
           which is required by `&[usize]: IntoFuture`
           `&mut [usize]: Future`
           which is required by `&mut [usize]: IntoFuture`
error[E0752]: `main` function is not allowed to be `async`
##[error]  --> /checkout/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.rs:6:1
   |
LL | async fn main() {
LL | async fn main() {
   | ^^^^^^^^^^^^^^^ `main` function is not allowed to be `async`
error: aborting due to 2 previous errors

Some errors have detailed explanations: E0599, E0752.
For more information about an error, try `rustc --explain E0599`.
---
- error[E0277]: `Option<_>` is not a future
+ error[E0599]: the method `into_future` exists for enum `Option<_>`, but its trait bounds were not satisfied
10   --> $DIR/drop-track-bad-field-in-fru.rs:6:46
11    |
12 LL |     None { value: (), ..Default::default() }.await;
-    |                                             -^^^^^
-    |                                             ||
-    |                                             |`Option<_>` is not a future
-    |                                             help: remove the `.await`
-    |                                             help: remove the `.await`
+    |                                              ^^^^^
17    |
-    = help: the trait `Future` is not implemented for `Option<_>`, which is required by `Option<_>: IntoFuture`
-    = note: Option<_> must be a future or must implement `IntoFuture` to be awaited
-    = note: required for `Option<_>` to implement `IntoFuture`
+    = note: the following trait bounds were not satisfied:
+            `Option<_>: Future`
+            which is required by `Option<_>: IntoFuture`
+            `&Option<_>: Future`
+            which is required by `&Option<_>: IntoFuture`
+            `&mut Option<_>: Future`
+            which is required by `&mut Option<_>: IntoFuture`
22 error: aborting due to 2 previous errors
23 

- Some errors have detailed explanations: E0277, E0559.
- Some errors have detailed explanations: E0277, E0559.
- For more information about an error, try `rustc --explain E0277`.
+ Some errors have detailed explanations: E0559, E0599.
+ For more information about an error, try `rustc --explain E0559`.
26 


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/async-await/drop-track-bad-field-in-fru/drop-track-bad-field-in-fru.stderr
To only update this specific test, also pass `--test-args async-await/drop-track-bad-field-in-fru.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
status: exit status: 1
command: RUSTC_ICE="0" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/async-await/drop-track-bad-field-in-fru.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/async-await/drop-track-bad-field-in-fru" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/async-await/drop-track-bad-field-in-fru/auxiliary" "--edition=2021"
--- stderr -------------------------------
--- stderr -------------------------------
error[E0559]: variant `Option<_>::None` has no field named `value`
   |
   |
LL |     None { value: (), ..Default::default() }.await;
   |            ^^^^^ `Option<_>::None` does not have this field
   = note: all struct fields are already assigned

error[E0599]: the method `into_future` exists for enum `Option<_>`, but its trait bounds were not satisfied
##[error]  --> /checkout/tests/ui/async-await/drop-track-bad-field-in-fru.rs:6:46
##[error]  --> /checkout/tests/ui/async-await/drop-track-bad-field-in-fru.rs:6:46
   |
LL |     None { value: (), ..Default::default() }.await;
   |
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `Option<_>: Future`
           which is required by `Option<_>: IntoFuture`
           `&Option<_>: Future`
           which is required by `&Option<_>: IntoFuture`
           `&mut Option<_>: Future`
           which is required by `&mut Option<_>: IntoFuture`
error: aborting due to 2 previous errors

Some errors have detailed explanations: E0559, E0599.
For more information about an error, try `rustc --explain E0559`.
---
4 LL |         .await

-    |         -^^^^^
-    |         ||
-    |         |`()` is not a future
-    |         help: remove the `.await`
+    |          ^^^^^ `()` is not a future
9    |
-    = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
-    = note: () must be a future or must implement `IntoFuture` to be awaited
-    = note: required for `()` to implement `IntoFuture`
+    = note: the following trait bounds were not satisfied:
+            `(): Future`
+            which is required by `(): IntoFuture`
+            `&(): Future`
+            which is required by `&(): IntoFuture`
+            `&mut (): Future`
+            which is required by `&mut (): IntoFuture`
14 error: aborting due to 1 previous error
15 

- For more information about this error, try `rustc --explain E0277`.
---
To only update this specific test, also pass `--test-args async-await/issue-101715.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: RUSTC_ICE="0" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/async-await/issue-101715.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/async-await/issue-101715" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/async-await/issue-101715/auxiliary" "--edition=2018"
--- stderr -------------------------------
error[E0599]: `()` is not a future
##[error]  --> /checkout/tests/ui/async-await/issue-101715.rs:11:10
   |
   |
LL |         .await
   |          ^^^^^ `()` is not a future
   |
   = note: the following trait bounds were not satisfied:
           `(): Future`
           which is required by `(): IntoFuture`
           `&(): Future`
           which is required by `&(): IntoFuture`
           `&mut (): Future`
           which is required by `&mut (): IntoFuture`
error: aborting due to 1 previous error

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


---- [ui] tests/ui/async-await/issue-98634.rs stdout ----
diff of stderr:

- error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
-   --> $DIR/issue-98634.rs:45:23
+ error[E0599]: `StructAsync<fn() -> impl Future<Output = ()> {callback}>` is not a future
3    |
3    |
- LL |         StructAsync { callback }.await;
-    |                       ^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found future
- note: required by a bound in `StructAsync`
-   --> $DIR/issue-98634.rs:9:35
-    |
-    |
10 LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
-    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync`
- 
- error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
-    |
-    |
+    | -------------------------------------------------------------------- method `into_future` not found for this struct because it doesn't satisfy `_: Future` or `_: IntoFuture`
+ ...
16 LL |         StructAsync { callback }.await;
-    |         ^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found future
+    |                                  ^^^^^ `StructAsync<fn() -> impl Future<Output = ()> {callback}>` is not a future
- note: required by a bound in `StructAsync`
-   --> $DIR/issue-98634.rs:9:35
-    |
-    |
- LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
-    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync`
+    = note: the following trait bounds were not satisfied:
+            `StructAsync<fn() -> impl Future<Output = ()> {callback}>: Future`
+            which is required by `StructAsync<fn() -> impl Future<Output = ()> {callback}>: IntoFuture`
+            `&StructAsync<fn() -> impl Future<Output = ()> {callback}>: Future`
+            which is required by `&StructAsync<fn() -> impl Future<Output = ()> {callback}>: IntoFuture`
+            `&mut StructAsync<fn() -> impl Future<Output = ()> {callback}>: Future`
+            which is required by `&mut StructAsync<fn() -> impl Future<Output = ()> {callback}>: IntoFuture`
+ note: the trait `Future` must be implemented
+   --> $SRC_DIR/core/src/future/future.rs:LL:COL
+    = help: items from traits can only be used if the trait is implemented and in scope
+    = note: the following trait defines an item `into_future`, perhaps you need to implement it:
+            candidate #1: `IntoFuture`
24 
25 error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
+   --> $DIR/issue-98634.rs:45:23
27    |
27    |
28 LL |         StructAsync { callback }.await;
-    |                                  ^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found future
+    |                       ^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found future
31 note: required by a bound in `StructAsync`
32   --> $DIR/issue-98634.rs:9:35


34 LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
35    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync`
- error: aborting due to 3 previous errors
+ error: aborting due to 2 previous errors
38 
- For more information about this error, try `rustc --explain E0271`.
---
To only update this specific test, also pass `--test-args async-await/issue-98634.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: RUSTC_ICE="0" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/async-await/issue-98634.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/async-await/issue-98634" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/async-await/issue-98634/auxiliary" "--edition=2021"
--- stderr -------------------------------
--- stderr -------------------------------
error[E0599]: `StructAsync<fn() -> impl Future<Output = ()> {callback}>` is not a future
   |
   |
LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
   | -------------------------------------------------------------------- method `into_future` not found for this struct because it doesn't satisfy `_: Future` or `_: IntoFuture`
...
LL |         StructAsync { callback }.await;
   |                                  ^^^^^ `StructAsync<fn() -> impl Future<Output = ()> {callback}>` is not a future
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `StructAsync<fn() -> impl Future<Output = ()> {callback}>: Future`
           which is required by `StructAsync<fn() -> impl Future<Output = ()> {callback}>: IntoFuture`
           `&StructAsync<fn() -> impl Future<Output = ()> {callback}>: Future`
           which is required by `&StructAsync<fn() -> impl Future<Output = ()> {callback}>: IntoFuture`
           `&mut StructAsync<fn() -> impl Future<Output = ()> {callback}>: Future`
           which is required by `&mut StructAsync<fn() -> impl Future<Output = ()> {callback}>: IntoFuture`
note: the trait `Future` must be implemented
  --> /rustc/FAKE_PREFIX/library/core/src/future/future.rs:35:1
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `into_future`, perhaps you need to implement it:
           candidate #1: `IntoFuture`

error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
   |
   |
LL |         StructAsync { callback }.await;
   |                       ^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found future
note: required by a bound in `StructAsync`
  --> /checkout/tests/ui/async-await/issue-98634.rs:9:35
   |
   |
LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync`
error: aborting due to 2 previous errors

Some errors have detailed explanations: E0271, E0599.
For more information about an error, try `rustc --explain E0271`.
---
- error[E0277]: `()` is not a future
+ error[E0599]: `()` is not a future
2   --> $DIR/unnecessary-await.rs:9:11
3    |
4 LL |     boo().await;
-    |     ----- ^^^^^ `()` is not a future
-    |     |
-    |     this call returns `()`
+    |           ^^^^^ `()` is not a future
+    |           ^^^^^ `()` is not a future
8    |
-    = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
-    = note: () must be a future or must implement `IntoFuture` to be awaited
-    = note: required for `()` to implement `IntoFuture`
- help: remove the `.await`
-    |
- LL -     boo().await;
- LL +     boo();
-    |
- help: alternatively, consider making `fn boo` asynchronous
-    |
- LL | async fn boo() {}
-    | +++++
+    = note: the following trait bounds were not satisfied:
+            `(): Future`
+            which is required by `(): IntoFuture`
+            `&(): Future`
+            which is required by `&(): IntoFuture`
+            `&mut (): Future`
+            which is required by `&mut (): IntoFuture`
- error[E0277]: `()` is not a future
+ error[E0599]: `()` is not a future
23   --> $DIR/unnecessary-await.rs:28:10
24    |
24    |
25 LL |     e!().await;
-    |         -^^^^^
-    |         ||
-    |         ||
-    |         |`()` is not a future
-    |         help: remove the `.await`
+    |          ^^^^^ `()` is not a future
30    |
-    = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
-    = note: () must be a future or must implement `IntoFuture` to be awaited
-    = note: required for `()` to implement `IntoFuture`
+    = note: the following trait bounds were not satisfied:
+            `(): Future`
+            which is required by `(): IntoFuture`
+            `&(): Future`
+            which is required by `&(): IntoFuture`
+            `&mut (): Future`
+            which is required by `&mut (): IntoFuture`
- error[E0277]: `()` is not a future
+ error[E0599]: `()` is not a future
36   --> $DIR/unnecessary-await.rs:22:15
37    |
37    |
38 LL |         $expr.await
-    |               ^^^^^
-    |               |
-    |               `()` is not a future
-    |               remove the `.await`
-    |               remove the `.await`
+    |               ^^^^^ `()` is not a future
43 ...
44 LL |     f!(());

46    |
46    |
-    = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
-    = note: () must be a future or must implement `IntoFuture` to be awaited
-    = note: required for `()` to implement `IntoFuture`
+    = note: the following trait bounds were not satisfied:
+            `(): Future`
+            which is required by `(): IntoFuture`
+            `&(): Future`
+            which is required by `&(): IntoFuture`
+            `&mut (): Future`
+            which is required by `&mut (): IntoFuture`
50    = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info)
- error[E0277]: `()` is not a future
+ error[E0599]: `()` is not a future
53   --> $DIR/unnecessary-await.rs:36:20
54    |
54    |
55 LL |     for x in [] {}.await
-    |                   -^^^^^
-    |                   ||
-    |                   ||
-    |                   |`()` is not a future
-    |                   help: remove the `.await`
+    |                    ^^^^^ `()` is not a future
60    |
-    = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
-    = note: () must be a future or must implement `IntoFuture` to be awaited
-    = note: required for `()` to implement `IntoFuture`
+    = note: the following trait bounds were not satisfied:
+            `(): Future`
+            which is required by `(): IntoFuture`
+            `&(): Future`
+            which is required by `&(): IntoFuture`
+            `&mut (): Future`
+            which is required by `&mut (): IntoFuture`
65 error: aborting due to 4 previous errors
66 

- For more information about this error, try `rustc --explain E0277`.
---
--- stderr -------------------------------
error[E0599]: `()` is not a future
##[error]  --> /checkout/tests/ui/async-await/unnecessary-await.rs:9:11
   |
LL |     boo().await; //~ ERROR `()` is not a future
   |           ^^^^^ `()` is not a future
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `(): Future`
           which is required by `(): IntoFuture`
           `&(): Future`
           which is required by `&(): IntoFuture`
           `&mut (): Future`
           which is required by `&mut (): IntoFuture`
error[E0599]: `()` is not a future
##[error]  --> /checkout/tests/ui/async-await/unnecessary-await.rs:28:10
   |
   |
LL |     e!().await;
   |          ^^^^^ `()` is not a future
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `(): Future`
           which is required by `(): IntoFuture`
           `&(): Future`
           which is required by `&(): IntoFuture`
           `&mut (): Future`
           which is required by `&mut (): IntoFuture`
error[E0599]: `()` is not a future
##[error]  --> /checkout/tests/ui/async-await/unnecessary-await.rs:22:15
   |
   |
LL |         $expr.await
   |               ^^^^^ `()` is not a future
...
LL |     f!(());
   |
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `(): Future`
           which is required by `(): IntoFuture`
           `&(): Future`
           which is required by `&(): IntoFuture`
           `&mut (): Future`
           which is required by `&mut (): IntoFuture`
   = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0599]: `()` is not a future
##[error]  --> /checkout/tests/ui/async-await/unnecessary-await.rs:36:20
   |
   |
LL |     for x in [] {}.await //~ ERROR `()` is not a future
   |                    ^^^^^ `()` is not a future
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `(): Future`
           which is required by `(): IntoFuture`
           `&(): Future`
           which is required by `&(): IntoFuture`
           `&mut (): Future`
           which is required by `&mut (): IntoFuture`
error: aborting due to 4 previous errors

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


---- [ui] tests/ui/coroutine/unresolved-ct-var.rs stdout ----
diff of stderr:

- error[E0277]: `[(); _]` is not a future
+ error[E0599]: `[(); _]` is not a future
3    |
3    |
4 LL |         let s = std::array::from_fn(|_| ()).await;
-    |                 ----------------------------^^^^^
-    |                 |                          ||
-    |                 |                          ||
-    |                 |                          |`[(); _]` is not a future
-    |                 |                          help: remove the `.await`
-    |                 this call returns `[(); _]`
+    |                                             ^^^^^ `[(); _]` is not a future
10    |
-    = help: the trait `Future` is not implemented for `[(); _]`, which is required by `[(); _]: IntoFuture`
-    = note: [(); _] must be a future or must implement `IntoFuture` to be awaited
-    = note: required for `[(); _]` to implement `IntoFuture`
+    = note: the following trait bounds were not satisfied:
+            `[(); _]: Future`
+            which is required by `[(); _]: IntoFuture`
+            `&[(); _]: Future`
+            which is required by `&[(); _]: IntoFuture`
+            `&mut [(); _]: Future`
+            which is required by `&mut [(); _]: IntoFuture`
+            `&[()]: Future`
+            which is required by `&[()]: IntoFuture`
+            `&mut [()]: Future`
+            which is required by `&mut [()]: IntoFuture`
15 error: aborting due to 1 previous error
16 

- For more information about this error, try `rustc --explain E0277`.
---
To only update this specific test, also pass `--test-args coroutine/unresolved-ct-var.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: RUSTC_ICE="0" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/coroutine/unresolved-ct-var.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "-C" "incremental=/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/coroutine/unresolved-ct-var/unresolved-ct-var.inc" "-Z" "incremental-verify-ich" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/coroutine/unresolved-ct-var" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/coroutine/unresolved-ct-var/auxiliary" "--edition=2021"
--- stderr -------------------------------
--- stderr -------------------------------
error[E0599]: `[(); _]` is not a future
   |
   |
LL |         let s = std::array::from_fn(|_| ()).await;
   |                                             ^^^^^ `[(); _]` is not a future
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `[(); _]: Future`
           which is required by `[(); _]: IntoFuture`
           `&[(); _]: Future`
           which is required by `&[(); _]: IntoFuture`
           `&mut [(); _]: Future`
           which is required by `&mut [(); _]: IntoFuture`
           `&[()]: Future`
           which is required by `&[()]: IntoFuture`
           `&mut [()]: Future`
           which is required by `&mut [()]: IntoFuture`
error: aborting due to 1 previous error

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


---- [ui] tests/ui/impl-trait/issue-103181-1.rs#current stdout ----
diff of stderr:

+ error[E0599]: `Server<(), MakeServiceFn<{closure@$DIR/issue-103181-1.rs:84:40: 84:42}>>` is not a future
+    |
+    |
+ LL |     pub struct Server<I, S>(I, S);
+    |     ----------------------- method `into_future` not found for this struct because it doesn't satisfy `_: Future` or `_: IntoFuture`
+ ...
+ LL |     hyper::serve::<(), _>(service).await;
+    |                                    ^^^^^ `Server<(), MakeServiceFn<{closure@$DIR/issue-103181-1.rs:84:40: 84:42}>>` is not a future
+    = note: the following trait bounds were not satisfied:
+    = note: the following trait bounds were not satisfied:
+            `Server<(), MakeServiceFn<{closure@$DIR/issue-103181-1.rs:84:40: 84:42}>>: Future`
+            which is required by `Server<(), MakeServiceFn<{closure@$DIR/issue-103181-1.rs:84:40: 84:42}>>: IntoFuture`
+            `&Server<(), MakeServiceFn<{closure@$DIR/issue-103181-1.rs:84:40: 84:42}>>: Future`
+            which is required by `&Server<(), MakeServiceFn<{closure@$DIR/issue-103181-1.rs:84:40: 84:42}>>: IntoFuture`
+            `&mut Server<(), MakeServiceFn<{closure@$DIR/issue-103181-1.rs:84:40: 84:42}>>: Future`
+            which is required by `&mut Server<(), MakeServiceFn<{closure@$DIR/issue-103181-1.rs:84:40: 84:42}>>: IntoFuture`
+ note: the trait `Future` must be implemented
+   --> $SRC_DIR/core/src/future/future.rs:LL:COL
+    = help: items from traits can only be used if the trait is implemented and in scope
+    = note: the following trait defines an item `into_future`, perhaps you need to implement it:
+            candidate #1: `IntoFuture`
1 error[E0046]: not all trait items implemented, missing: `Error`
2   --> $DIR/issue-103181-1.rs:12:5
3    |

---
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/impl-trait/issue-103181-1.current/issue-103181-1.current.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args impl-trait/issue-103181-1.rs`

error in revision `current`: 1 errors occurred comparing output.
status: exit status: 1
command: RUSTC_ICE="0" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/impl-trait/issue-103181-1.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--cfg" "current" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/impl-trait/issue-103181-1.current" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/impl-trait/issue-103181-1.current/auxiliary" "--edition=2021"
--- stderr -------------------------------
--- stderr -------------------------------
error[E0599]: `Server<(), MakeServiceFn<{closure@/checkout/tests/ui/impl-trait/issue-103181-1.rs:84:40: 84:42}>>` is not a future
   |
   |
LL |     pub struct Server<I, S>(I, S);
   |     ----------------------- method `into_future` not found for this struct because it doesn't satisfy `_: Future` or `_: IntoFuture`
...
LL |     hyper::serve::<(), _>(service).await;
   |                                    ^^^^^ `Server<(), MakeServiceFn<{closure@/checkout/tests/ui/impl-trait/issue-103181-1.rs:84:40: 84:42}>>` is not a future
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `Server<(), MakeServiceFn<{closure@/checkout/tests/ui/impl-trait/issue-103181-1.rs:84:40: 84:42}>>: Future`
           which is required by `Server<(), MakeServiceFn<{closure@/checkout/tests/ui/impl-trait/issue-103181-1.rs:84:40: 84:42}>>: IntoFuture`
           `&Server<(), MakeServiceFn<{closure@/checkout/tests/ui/impl-trait/issue-103181-1.rs:84:40: 84:42}>>: Future`
           which is required by `&Server<(), MakeServiceFn<{closure@/checkout/tests/ui/impl-trait/issue-103181-1.rs:84:40: 84:42}>>: IntoFuture`
           `&mut Server<(), MakeServiceFn<{closure@/checkout/tests/ui/impl-trait/issue-103181-1.rs:84:40: 84:42}>>: Future`
           which is required by `&mut Server<(), MakeServiceFn<{closure@/checkout/tests/ui/impl-trait/issue-103181-1.rs:84:40: 84:42}>>: IntoFuture`
note: the trait `Future` must be implemented
  --> /rustc/FAKE_PREFIX/library/core/src/future/future.rs:35:1
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `into_future`, perhaps you need to implement it:
           candidate #1: `IntoFuture`
error[E0046]: not all trait items implemented, missing: `Error`
##[error]  --> /checkout/tests/ui/impl-trait/issue-103181-1.rs:12:5
   |
LL |         type Error;
---
- error[E0277]: `()` is not a future
+ error[E0599]: `()` is not a future
2   --> $DIR/issue-96555.rs:4:13
3    |
4 LL |     m::f1().await;
-    |     ------- ^^^^^ `()` is not a future
-    |     |
-    |     this call returns `()`
+    |             ^^^^^ `()` is not a future
+    |             ^^^^^ `()` is not a future
8    |
-    = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
-    = note: () must be a future or must implement `IntoFuture` to be awaited
-    = note: required for `()` to implement `IntoFuture`
- help: remove the `.await`
-    |
- LL -     m::f1().await;
- LL +     m::f1();
-    |
- help: alternatively, consider making `fn f1` asynchronous
- LL |     pub async fn f1() {}
-    |         +++++
+    = note: the following trait bounds were not satisfied:
+    = note: the following trait bounds were not satisfied:
+            `(): Future`
+            which is required by `(): IntoFuture`
+            `&(): Future`
+            which is required by `&(): IntoFuture`
+            `&mut (): Future`
+            which is required by `&mut (): IntoFuture`
- error[E0277]: `()` is not a future
+ error[E0599]: `()` is not a future
23   --> $DIR/issue-96555.rs:5:13
24    |
24    |
25 LL |     m::f2().await;
-    |     ------- ^^^^^ `()` is not a future
-    |     |
-    |     this call returns `()`
+    |             ^^^^^ `()` is not a future
+    |             ^^^^^ `()` is not a future
29    |
-    = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
-    = note: () must be a future or must implement `IntoFuture` to be awaited
-    = note: required for `()` to implement `IntoFuture`
- help: remove the `.await`
-    |
- LL -     m::f2().await;
- LL +     m::f2();
-    |
- help: alternatively, consider making `fn f2` asynchronous
-    |
- LL |     pub(crate) async fn f2() {}
+    = note: the following trait bounds were not satisfied:
+    = note: the following trait bounds were not satisfied:
+            `(): Future`
+            which is required by `(): IntoFuture`
+            `&(): Future`
+            which is required by `&(): IntoFuture`
+            `&mut (): Future`
+            which is required by `&mut (): IntoFuture`
- error[E0277]: `()` is not a future
+ error[E0599]: `()` is not a future
44   --> $DIR/issue-96555.rs:6:13
45    |
45    |
46 LL |     m::f3().await;
-    |     ------- ^^^^^ `()` is not a future
-    |     |
-    |     this call returns `()`
+    |             ^^^^^ `()` is not a future
+    |             ^^^^^ `()` is not a future
50    |
-    = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
-    = note: () must be a future or must implement `IntoFuture` to be awaited
-    = note: required for `()` to implement `IntoFuture`
- help: remove the `.await`
-    |
- LL -     m::f3().await;
- LL +     m::f3();
-    |
- help: alternatively, consider making `fn f3` asynchronous
- LL |     pub async
-    |         +++++
+    = note: the following trait bounds were not satisfied:
+    = note: the following trait bounds were not satisfied:
+            `(): Future`
+            which is required by `(): IntoFuture`
+            `&(): Future`
+            which is required by `&(): IntoFuture`
+            `&mut (): Future`
+            which is required by `&mut (): IntoFuture`
64 error: aborting due to 3 previous errors
65 

- For more information about this error, try `rustc --explain E0277`.
---
To only update this specific test, also pass `--test-args suggestions/issue-96555.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: RUSTC_ICE="0" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/suggestions/issue-96555.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/suggestions/issue-96555" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/suggestions/issue-96555/auxiliary" "--edition=2018"
--- stderr -------------------------------
error[E0599]: `()` is not a future
##[error]  --> /checkout/tests/ui/suggestions/issue-96555.rs:4:13
   |
   |
LL |     m::f1().await; //~ ERROR `()` is not a future
   |             ^^^^^ `()` is not a future
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `(): Future`
           which is required by `(): IntoFuture`
           `&(): Future`
           which is required by `&(): IntoFuture`
           `&mut (): Future`
           which is required by `&mut (): IntoFuture`
error[E0599]: `()` is not a future
##[error]  --> /checkout/tests/ui/suggestions/issue-96555.rs:5:13
   |
   |
LL |     m::f2().await; //~ ERROR `()` is not a future
   |             ^^^^^ `()` is not a future
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `(): Future`
           which is required by `(): IntoFuture`
           `&(): Future`
           which is required by `&(): IntoFuture`
           `&mut (): Future`
           which is required by `&mut (): IntoFuture`
error[E0599]: `()` is not a future
##[error]  --> /checkout/tests/ui/suggestions/issue-96555.rs:6:13
   |
   |
LL |     m::f3().await; //~ ERROR `()` is not a future
   |             ^^^^^ `()` is not a future
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `(): Future`
           which is required by `(): IntoFuture`
           `&(): Future`
           which is required by `&(): IntoFuture`
           `&mut (): Future`
           which is required by `&mut (): IntoFuture`
error: aborting due to 3 previous errors

Build completed unsuccessfully in 0:14:08
For more information about this error, try `rustc --explain E0599`.

@Jules-Bertholet
Copy link
Contributor Author

Jules-Bertholet commented Mar 25, 2024

We discussed this in the async triage meeting today. One thing we wanted to see here that we haven't yet is a full analysis of the crater run. We'd want to see all of the root regressions analyzed in the report. And for each of those, we'd be interested in seeing what the suggested fix or workaround would be.

I'll put together something more complete when I have time, but to start with, here's an analysis of the single root regression responsible for ~95% of crater failures:

https://github.com/smithy-lang/smithy-rs/blob/1487391b1894c32f8479dd1105c9e80aef41d150/rust-runtime/aws-smithy-runtime/src/client/orchestrator.rs#L282-L337

let mut retry_delay = None;
for i in 1u32.. {
    /* ... */
    if let Some((delay, sleep)) = retry_delay.take() {
        debug!("delaying for {delay:?}");
        sleep.await;
    }
    /* ... */
    retry_delay = Some((delay, sleep_impl.sleep(delay))); // type of `retry_delay` is constrained here
}

Without this change, it compiles fine. With this change, we get:

error[E0282]: type annotations needed for `std::option::Option<(_, _)>`
   --> aws-smithy-runtime/src/client/orchestrator.rs:282:9
    |
282 |     let mut retry_delay = None;
    |         ^^^^^^^^^^^^^^^
...
297 |             sleep.await;
    |             ----- type must be known at this point
    |
help: consider giving `retry_delay` an explicit type, where the placeholders `_` are specified
    |
282 |     let mut retry_delay: std::option::Option<(_, _)> = None;
    |                        +++++++++++++++++++++++++++++

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

Adding a type annotation as suggested by the compiler makes the code compile again.

Would the plan be to target Rust 2024? [...] And, to confirm, would the plan be to maintain indefinitely the different desugaring in the older editions?

That's up to the relevant teams to decide. However, I am skeptical, as maintaining two implementations of await desugaring indefinitely would be a burden. And the number of directly affected crates is quite limited

If so, what would the migration strategy be?

Automated migration would be difficult I think (don't know enough about type system implementation to say for sure). However, as the example above shows, the compiler error is pretty good, and it's easy to apply the fix manually.


From the triage meeting minutes:

CE: We'd need to do this over an edition, and then we'd have two implementations of the .await operator.

CE: Postfix macros can't autoderef. It doesn't make sense for postfix match either. Match already has match ergonomics. [...]

TC: Consistency with postfix macros does seem compelling.

CE: Indeed, it is essentially a postfix macro.

I have a mental model here that is perhaps slightly different. Non-type-directed postifx macros as proposed in rust-lang/rfcs#2442, as well as postfix match, don't impose any restrictions on the type of their receiver. They are analogous to a method of a trait with a blanket impl for any T. And like such a method, they don't perform auto(de)ref because there are no type system constraints to guide such. Notably, one could imagine a future Rust getting postfix macros with type-based dispatch (which is what .await would be analogous to); and I would expect those to have auto(de)ref.

@compiler-errors
Copy link
Member

compiler-errors commented Mar 25, 2024

Notably, one could imagine a future Rust getting postfix macros with type-based dispatch; and I would expect those to have auto(de)ref.

For the record, I don't see such a future being possible, at least not with an incredible amount of work and churn to the compiler implementation. Macro expansion happens before name resolution and operates on the AST level, and type checking operates on HIR only after macro expansion. I don't think we should be designing features (reworded slightly:) making design decisions based off of analogy to things that aren't likely to happen to Rust.

@Jules-Bertholet
Copy link
Contributor Author

Jules-Bertholet commented Mar 25, 2024

I don't think we should be designing features (reworded slightly:) making design decisions based off of analogy to things that aren't likely to happen to Rust.

I don't see the implementation feasibility (or lack of such) of type-directed postfix macros as relevant to my argument. My point is, analogizing between .await (which is type-directed with IntoFuture) and postfix macros/rust-lang/rfcs#2442 postfix match (which are not type-directed) is not illuminating; the correct analogy is with features (real or imagined) sharing the same level of type-directedness, and such an analogy suggests .await should auto(de)ref.

@oli-obk
Copy link
Contributor

oli-obk commented Mar 26, 2024

which is type-directed with IntoFuture

What do you mean by that? You can write a macro_rules macro today that does the equivalent of await. It gets expanded to something using the IntoFuture trait, but there's nobtype based logic happening on the await

@Jules-Bertholet
Copy link
Contributor Author

which is type-directed with IntoFuture

What do you mean by that? You can write a macro_rules macro today that does the equivalent of await. It gets expanded to something using the IntoFuture trait, but there's nobtype based logic happening on the await

Hmm, you're right I guess. But if you were to write such a postfix macro, you would probably use method call syntax ($expr.into_future()), and therefore auto(de)ref, no? Or at the very least, you'd have the option of doing so.

@oli-obk
Copy link
Contributor

oli-obk commented Mar 27, 2024

and therefore auto(de)ref, no? Or at the very least, you'd have the option of doing so.

no, that is not possible in general, because it won't know that it should pick up IntoFuture::into_future and will just duck-type the into_future method call. Also you get very different inference behaviour from method calls and UFCs, so that would cause more problems similar to the ones found by crater

@Jules-Bertholet
Copy link
Contributor Author

Jules-Bertholet commented Mar 27, 2024

no, that is not possible in general, because it won't know that it should pick up IntoFuture::into_future and will just duck-type the into_future method call.

Where there's a will, there's a way:

// On stable
use ::core::future::IntoFuture;

#[doc(hidden)]
pub trait IntoFutureUnambiguous: IntoFuture {
    fn __into_futureඞunambiguousඞ(self) -> Self::IntoFuture;
}

impl<T: IntoFuture> IntoFutureUnambiguous for T {
    fn __into_futureඞunambiguousඞ(self) -> Self::IntoFuture {
        self.into_future()
    }
}

#[macro_export]
macro_rules! into_future_with_autoref {
    ($expr:expr) => {
        use $crate::IntoFutureUnambiguous;
        ($expr).__into_futureඞunambiguousඞ()
    };
}
// On nightly, with `decl_macro`
#![feature(decl_macro)]
#[doc(hidden)]
pub use core::future::IntoFuture;
pub macro into_future_with_autoref($expr:expr) {
    use $crate::IntoFuture;
    $expr.into_future()
}
// On nightly, with `proc_macro_def_site`
#![feature(proc_macro_def_site)]
extern crate proc_macro;
use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
#[proc_macro]
pub fn into_future_autoref(ts: TokenStream) -> TokenStream {
    let def_span = Span::def_site();
    TokenStream::from_iter([
        TokenTree::Ident(Ident::new("use", def_span)),
        TokenTree::Punct(Punct::new(':', Spacing::Joint)),
        TokenTree::Punct(Punct::new(':', Spacing::Alone)),
        TokenTree::Ident(Ident::new("core", def_span)),
        TokenTree::Punct(Punct::new(':', Spacing::Joint)),
        TokenTree::Punct(Punct::new(':', Spacing::Alone)),
        TokenTree::Ident(Ident::new("future", def_span)),
        TokenTree::Punct(Punct::new(':', Spacing::Joint)),
        TokenTree::Punct(Punct::new(':', Spacing::Alone)),
        TokenTree::Ident(Ident::new("IntoFuture", def_span)),
        TokenTree::Punct(Punct::new(';', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::None, ts)),
        TokenTree::Punct(Punct::new('.', Spacing::Alone)),
        TokenTree::Ident(Ident::new(
            "into_future",
            def_span.located_at(Span::call_site()),
        )),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ])
}

@oli-obk
Copy link
Contributor

oli-obk commented Mar 27, 2024

From the complexity of the solutions, I am wondering if this is worth it for the niche use case that it satisfies. If we have this complexity for single digit usages in crates.io, then it's not worth it imo.

As Esteban noted, we can just produce high quality diagnostics instead. Not every use case needs lang support. A simpler language with diagnostics catching all the hypothetical language features and suggesting existing lang features is also nice

@Jules-Bertholet
Copy link
Contributor Author

The complexity of a good diagnostic would be comparable to or greater than that of a full implementation, no?

@oli-obk
Copy link
Contributor

oli-obk commented Mar 28, 2024

No. We'd be extending an existing diagnostic, and it would not be part of the type system, so its complexity is not as relevent, as we can change it at any time.

@bors
Copy link
Contributor

bors commented Apr 23, 2024

☔ The latest upstream changes (presumably #122317) made this pull request unmergeable. Please resolve the merge conflicts.

@oli-obk
Copy link
Contributor

oli-obk commented Apr 23, 2024

I'm going to close this, because I believe it is adding too much complexity to the compiler, while having not a motivating enough (in quantity) language use case. I am fine revisiting this implementation work should T-lang decide this is desirable, even if I personally do not think it is, or that T-lang should spend time on this, considering everything else they have on their plate.

@oli-obk oli-obk closed this Apr 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue. WG-async Working group: Async & await
Projects
None yet
Development

Successfully merging this pull request may close these issues.

.await does not perform autoref or autoderef