about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-02-29 13:35:16 +0000
committerbors <bors@rust-lang.org>2024-02-29 13:35:16 +0000
commit384d26fc7e3bdd7687cc17b2662b091f6017ec2a (patch)
tree92c1723144aab5f058f229272d70dbfe751444a1 /compiler
parent71a7b66f20c551f640f2f382bc7e7923ba0a5dab (diff)
parentbc23b843865fbfd1d585b133ac3006239021f5c4 (diff)
downloadrust-384d26fc7e3bdd7687cc17b2662b091f6017ec2a.tar.gz
rust-384d26fc7e3bdd7687cc17b2662b091f6017ec2a.zip
Auto merge of #121800 - GuillaumeGomez:rollup-wob2qcz, r=GuillaumeGomez
Rollup of 10 pull requests

Successful merges:

 - #118217 (Document which methods on `f64` are precise)
 - #119748 (Increase visibility of `join_path` and `split_paths`)
 - #121412 (platform docs: clarify hexagon-unknown-none-elf example, add hexagon-unknown-linux-musl)
 - #121654 (Fix `async Fn` confirmation for `FnDef`/`FnPtr`/`Closure` types)
 - #121700 (CFI: Don't compress user-defined builtin types)
 - #121765 (add platform-specific function to get the error number for HermitOS)
 - #121781 (bootstrap/format: send larger batches to rustfmt)
 - #121788 (bootstrap: fix clap deprecated warnings)
 - #121792 (Improve renaming suggestion when item starts with underscore)
 - #121793 (Document which methods on `f32` are precise)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs6
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs5
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs17
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs201
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs81
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs22
7 files changed, 252 insertions, 98 deletions
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 75613a2c555..733e2f93b25 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -37,7 +37,11 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
         }
         ty::InstanceDef::FnPtrShim(def_id, ty) => {
             let trait_ = tcx.trait_of_item(def_id).unwrap();
-            let adjustment = match tcx.fn_trait_kind_from_def_id(trait_) {
+            // Supports `Fn` or `async Fn` traits.
+            let adjustment = match tcx
+                .fn_trait_kind_from_def_id(trait_)
+                .or_else(|| tcx.async_fn_trait_kind_from_def_id(trait_))
+            {
                 Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
                 Some(ty::ClosureKind::Fn) => Adjustment::Deref { source: DerefSource::ImmRef },
                 Some(ty::ClosureKind::FnMut) => Adjustment::Deref { source: DerefSource::MutRef },
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index e4298a98129..6b45db7ba83 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1585,9 +1585,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         {
             // When the suggested binding change would be from `x` to `_x`, suggest changing the
             // original binding definition instead. (#60164)
-            (span, snippet, ", consider changing it")
+            let post = format!(", consider renaming `{}` into `{snippet}`", suggestion.candidate);
+            (span, snippet, post)
         } else {
-            (span, suggestion.candidate.to_string(), "")
+            (span, suggestion.candidate.to_string(), String::new())
         };
         let msg = match suggestion.target {
             SuggestionTarget::SimilarlyNamed => format!(
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 0d7b9afab5e..42d9b519c14 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -546,8 +546,20 @@ fn encode_ty<'tcx>(
             if let Some(cfi_encoding) = tcx.get_attr(def_id, sym::cfi_encoding) {
                 // Use user-defined CFI encoding for type
                 if let Some(value_str) = cfi_encoding.value_str() {
-                    if !value_str.to_string().trim().is_empty() {
-                        s.push_str(value_str.to_string().trim());
+                    let value_str = value_str.to_string();
+                    let str = value_str.trim();
+                    if !str.is_empty() {
+                        s.push_str(str);
+                        // Don't compress user-defined builtin types (see
+                        // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-builtin and
+                        // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
+                        let builtin_types = [
+                            "v", "w", "b", "c", "a", "h", "s", "t", "i", "j", "l", "m", "x", "y",
+                            "n", "o", "f", "d", "e", "g", "z",
+                        ];
+                        if !builtin_types.contains(&str) {
+                            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+                        }
                     } else {
                         #[allow(
                             rustc::diagnostic_outside_of_impl,
@@ -563,7 +575,6 @@ fn encode_ty<'tcx>(
                 } else {
                     bug!("encode_ty: invalid `cfi_encoding` for `{:?}`", ty.kind());
                 }
-                compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
             } else if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
                 // For cross-language LLVM CFI support, the encoding must be compatible at the FFI
                 // boundary. For instance:
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 3b902dd80f5..af533d8db71 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -281,7 +281,58 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
         }
 
         // Coroutine-closures don't implement `Fn` traits the normal way.
-        ty::CoroutineClosure(..) => Err(NoSolution),
+        // Instead, they always implement `FnOnce`, but only implement
+        // `FnMut`/`Fn` if they capture no upvars, since those may borrow
+        // from the closure.
+        ty::CoroutineClosure(def_id, args) => {
+            let args = args.as_coroutine_closure();
+            let kind_ty = args.kind_ty();
+            let sig = args.coroutine_closure_sig().skip_binder();
+
+            let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
+                if !closure_kind.extends(goal_kind) {
+                    return Err(NoSolution);
+                }
+
+                // If `Fn`/`FnMut`, we only implement this goal if we
+                // have no captures.
+                let no_borrows = match args.tupled_upvars_ty().kind() {
+                    ty::Tuple(tys) => tys.is_empty(),
+                    ty::Error(_) => false,
+                    _ => bug!("tuple_fields called on non-tuple"),
+                };
+                if closure_kind != ty::ClosureKind::FnOnce && !no_borrows {
+                    return Err(NoSolution);
+                }
+
+                coroutine_closure_to_certain_coroutine(
+                    tcx,
+                    goal_kind,
+                    // No captures by ref, so this doesn't matter.
+                    tcx.lifetimes.re_static,
+                    def_id,
+                    args,
+                    sig,
+                )
+            } else {
+                // Closure kind is not yet determined, so we return ambiguity unless
+                // the expected kind is `FnOnce` as that is always implemented.
+                if goal_kind != ty::ClosureKind::FnOnce {
+                    return Ok(None);
+                }
+
+                coroutine_closure_to_ambiguous_coroutine(
+                    tcx,
+                    goal_kind, // No captures by ref, so this doesn't matter.
+                    tcx.lifetimes.re_static,
+                    def_id,
+                    args,
+                    sig,
+                )
+            };
+
+            Ok(Some(args.coroutine_closure_sig().rebind((sig.tupled_inputs_ty, coroutine_ty))))
+        }
 
         ty::Bool
         | ty::Char
@@ -313,6 +364,19 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
     }
 }
 
+/// Relevant types for an async callable, including its inputs, output,
+/// and the return type you get from awaiting the output.
+#[derive(Copy, Clone, Debug, TypeVisitable, TypeFoldable)]
+pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> {
+    pub tupled_inputs_ty: Ty<'tcx>,
+    /// Type returned by calling the closure
+    /// i.e. `f()`.
+    pub output_coroutine_ty: Ty<'tcx>,
+    /// Type returned by `await`ing the output
+    /// i.e. `f().await`.
+    pub coroutine_return_ty: Ty<'tcx>,
+}
+
 // Returns a binder of the tupled inputs types, output type, and coroutine type
 // from a builtin coroutine-closure type. If we don't yet know the closure kind of
 // the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper`
@@ -323,8 +387,10 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
     self_ty: Ty<'tcx>,
     goal_kind: ty::ClosureKind,
     env_region: ty::Region<'tcx>,
-) -> Result<(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Vec<ty::Predicate<'tcx>>), NoSolution>
-{
+) -> Result<
+    (ty::Binder<'tcx, AsyncCallableRelevantTypes<'tcx>>, Vec<ty::Predicate<'tcx>>),
+    NoSolution,
+> {
     match *self_ty.kind() {
         ty::CoroutineClosure(def_id, args) => {
             let args = args.as_coroutine_closure();
@@ -335,24 +401,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
                 if !closure_kind.extends(goal_kind) {
                     return Err(NoSolution);
                 }
-                sig.to_coroutine_given_kind_and_upvars(
-                    tcx,
-                    args.parent_args(),
-                    tcx.coroutine_for_closure(def_id),
-                    goal_kind,
-                    env_region,
-                    args.tupled_upvars_ty(),
-                    args.coroutine_captures_by_ref_ty(),
+
+                coroutine_closure_to_certain_coroutine(
+                    tcx, goal_kind, env_region, def_id, args, sig,
                 )
             } else {
-                let async_fn_kind_trait_def_id =
-                    tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
-                let upvars_projection_def_id = tcx
-                    .associated_items(async_fn_kind_trait_def_id)
-                    .filter_by_name_unhygienic(sym::Upvars)
-                    .next()
-                    .unwrap()
-                    .def_id;
                 // When we don't know the closure kind (and therefore also the closure's upvars,
                 // which are computed at the same time), we must delay the computation of the
                 // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
@@ -363,38 +416,23 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
                 nested.push(
                     ty::TraitRef::new(
                         tcx,
-                        async_fn_kind_trait_def_id,
+                        tcx.require_lang_item(LangItem::AsyncFnKindHelper, None),
                         [kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
                     )
                     .to_predicate(tcx),
                 );
-                let tupled_upvars_ty = Ty::new_projection(
-                    tcx,
-                    upvars_projection_def_id,
-                    [
-                        ty::GenericArg::from(kind_ty),
-                        Ty::from_closure_kind(tcx, goal_kind).into(),
-                        env_region.into(),
-                        sig.tupled_inputs_ty.into(),
-                        args.tupled_upvars_ty().into(),
-                        args.coroutine_captures_by_ref_ty().into(),
-                    ],
-                );
-                sig.to_coroutine(
-                    tcx,
-                    args.parent_args(),
-                    Ty::from_closure_kind(tcx, goal_kind),
-                    tcx.coroutine_for_closure(def_id),
-                    tupled_upvars_ty,
+
+                coroutine_closure_to_ambiguous_coroutine(
+                    tcx, goal_kind, env_region, def_id, args, sig,
                 )
             };
 
             Ok((
-                args.coroutine_closure_sig().rebind((
-                    sig.tupled_inputs_ty,
-                    sig.return_ty,
-                    coroutine_ty,
-                )),
+                args.coroutine_closure_sig().rebind(AsyncCallableRelevantTypes {
+                    tupled_inputs_ty: sig.tupled_inputs_ty,
+                    output_coroutine_ty: coroutine_ty,
+                    coroutine_return_ty: sig.return_ty,
+                }),
                 nested,
             ))
         }
@@ -418,7 +456,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
                 .def_id;
             let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
             Ok((
-                bound_sig.rebind((Ty::new_tup(tcx, sig.inputs()), sig.output(), future_output_ty)),
+                bound_sig.rebind(AsyncCallableRelevantTypes {
+                    tupled_inputs_ty: Ty::new_tup(tcx, sig.inputs()),
+                    output_coroutine_ty: sig.output(),
+                    coroutine_return_ty: future_output_ty,
+                }),
                 nested,
             ))
         }
@@ -469,7 +511,14 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
                 .unwrap()
                 .def_id;
             let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
-            Ok((bound_sig.rebind((sig.inputs()[0], sig.output(), future_output_ty)), nested))
+            Ok((
+                bound_sig.rebind(AsyncCallableRelevantTypes {
+                    tupled_inputs_ty: sig.inputs()[0],
+                    output_coroutine_ty: sig.output(),
+                    coroutine_return_ty: future_output_ty,
+                }),
+                nested,
+            ))
         }
 
         ty::Bool
@@ -502,6 +551,68 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
     }
 }
 
+/// Given a coroutine-closure, project to its returned coroutine when we are *certain*
+/// that the closure's kind is compatible with the goal.
+fn coroutine_closure_to_certain_coroutine<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    goal_kind: ty::ClosureKind,
+    goal_region: ty::Region<'tcx>,
+    def_id: DefId,
+    args: ty::CoroutineClosureArgs<'tcx>,
+    sig: ty::CoroutineClosureSignature<'tcx>,
+) -> Ty<'tcx> {
+    sig.to_coroutine_given_kind_and_upvars(
+        tcx,
+        args.parent_args(),
+        tcx.coroutine_for_closure(def_id),
+        goal_kind,
+        goal_region,
+        args.tupled_upvars_ty(),
+        args.coroutine_captures_by_ref_ty(),
+    )
+}
+
+/// Given a coroutine-closure, project to its returned coroutine when we are *not certain*
+/// that the closure's kind is compatible with the goal, and therefore also don't know
+/// yet what the closure's upvars are.
+///
+/// Note that we do not also push a `AsyncFnKindHelper` goal here.
+fn coroutine_closure_to_ambiguous_coroutine<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    goal_kind: ty::ClosureKind,
+    goal_region: ty::Region<'tcx>,
+    def_id: DefId,
+    args: ty::CoroutineClosureArgs<'tcx>,
+    sig: ty::CoroutineClosureSignature<'tcx>,
+) -> Ty<'tcx> {
+    let async_fn_kind_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
+    let upvars_projection_def_id = tcx
+        .associated_items(async_fn_kind_trait_def_id)
+        .filter_by_name_unhygienic(sym::Upvars)
+        .next()
+        .unwrap()
+        .def_id;
+    let tupled_upvars_ty = Ty::new_projection(
+        tcx,
+        upvars_projection_def_id,
+        [
+            ty::GenericArg::from(args.kind_ty()),
+            Ty::from_closure_kind(tcx, goal_kind).into(),
+            goal_region.into(),
+            sig.tupled_inputs_ty.into(),
+            args.tupled_upvars_ty().into(),
+            args.coroutine_captures_by_ref_ty().into(),
+        ],
+    );
+    sig.to_coroutine(
+        tcx,
+        args.parent_args(),
+        Ty::from_closure_kind(tcx, goal_kind),
+        tcx.coroutine_for_closure(def_id),
+        tupled_upvars_ty,
+    )
+}
+
 /// Assemble a list of predicates that would be present on a theoretical
 /// user impl for an object type. These predicates must be checked any time
 /// we assemble a built-in object candidate for an object type, since they
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index aa8cc3667cd..3aba5c85abc 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -1,5 +1,6 @@
 use crate::traits::{check_args_compatible, specialization_graph};
 
+use super::assembly::structural_traits::AsyncCallableRelevantTypes;
 use super::assembly::{self, structural_traits, Candidate};
 use super::{EvalCtxt, GoalSource};
 use rustc_hir::def::DefKind;
@@ -392,46 +393,56 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                 goal_kind,
                 env_region,
             )?;
-        let output_is_sized_pred =
-            tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| {
-                ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
-            });
+        let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
+            |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| {
+                ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output_ty])
+            },
+        );
 
         let pred = tupled_inputs_and_output_and_coroutine
-            .map_bound(|(inputs, output, coroutine)| {
-                let (projection_ty, term) = match tcx.item_name(goal.predicate.def_id()) {
-                    sym::CallOnceFuture => (
-                        ty::AliasTy::new(
-                            tcx,
-                            goal.predicate.def_id(),
-                            [goal.predicate.self_ty(), inputs],
+            .map_bound(
+                |AsyncCallableRelevantTypes {
+                     tupled_inputs_ty,
+                     output_coroutine_ty,
+                     coroutine_return_ty,
+                 }| {
+                    let (projection_ty, term) = match tcx.item_name(goal.predicate.def_id()) {
+                        sym::CallOnceFuture => (
+                            ty::AliasTy::new(
+                                tcx,
+                                goal.predicate.def_id(),
+                                [goal.predicate.self_ty(), tupled_inputs_ty],
+                            ),
+                            output_coroutine_ty.into(),
                         ),
-                        coroutine.into(),
-                    ),
-                    sym::CallMutFuture | sym::CallFuture => (
-                        ty::AliasTy::new(
-                            tcx,
-                            goal.predicate.def_id(),
-                            [
-                                ty::GenericArg::from(goal.predicate.self_ty()),
-                                inputs.into(),
-                                env_region.into(),
-                            ],
+                        sym::CallMutFuture | sym::CallFuture => (
+                            ty::AliasTy::new(
+                                tcx,
+                                goal.predicate.def_id(),
+                                [
+                                    ty::GenericArg::from(goal.predicate.self_ty()),
+                                    tupled_inputs_ty.into(),
+                                    env_region.into(),
+                                ],
+                            ),
+                            output_coroutine_ty.into(),
                         ),
-                        coroutine.into(),
-                    ),
-                    sym::Output => (
-                        ty::AliasTy::new(
-                            tcx,
-                            goal.predicate.def_id(),
-                            [ty::GenericArg::from(goal.predicate.self_ty()), inputs.into()],
+                        sym::Output => (
+                            ty::AliasTy::new(
+                                tcx,
+                                goal.predicate.def_id(),
+                                [
+                                    ty::GenericArg::from(goal.predicate.self_ty()),
+                                    tupled_inputs_ty.into(),
+                                ],
+                            ),
+                            coroutine_return_ty.into(),
                         ),
-                        output.into(),
-                    ),
-                    name => bug!("no such associated type: {name}"),
-                };
-                ty::ProjectionPredicate { projection_ty, term }
-            })
+                        name => bug!("no such associated type: {name}"),
+                    };
+                    ty::ProjectionPredicate { projection_ty, term }
+                },
+            )
             .to_predicate(tcx);
 
         // A built-in `AsyncFn` impl only holds if the output is sized.
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 73bf66f6689..eba6ba3f7b0 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -2,6 +2,7 @@
 
 use crate::traits::supertrait_def_ids;
 
+use super::assembly::structural_traits::AsyncCallableRelevantTypes;
 use super::assembly::{self, structural_traits, Candidate};
 use super::{EvalCtxt, GoalSource, SolverMode};
 use rustc_data_structures::fx::FxIndexSet;
@@ -327,14 +328,19 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                 // This region doesn't matter because we're throwing away the coroutine type
                 tcx.lifetimes.re_static,
             )?;
-        let output_is_sized_pred =
-            tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| {
-                ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
-            });
+        let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
+            |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
+                ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output_coroutine_ty])
+            },
+        );
 
         let pred = tupled_inputs_and_output_and_coroutine
-            .map_bound(|(inputs, _, _)| {
-                ty::TraitRef::new(tcx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
+            .map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| {
+                ty::TraitRef::new(
+                    tcx,
+                    goal.predicate.def_id(),
+                    [goal.predicate.self_ty(), tupled_inputs_ty],
+                )
             })
             .to_predicate(tcx);
         // A built-in `AsyncFn` impl only holds if the output is sized.
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index d316149731e..b8733bab27b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -923,14 +923,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         [self_ty, Ty::new_tup(tcx, sig.inputs())],
                     )
                 });
+
                 // We must additionally check that the return type impls `Future`.
+
+                // FIXME(async_closures): Investigate this before stabilization.
+                // We instantiate this binder eagerly because the `confirm_future_candidate`
+                // method doesn't support higher-ranked futures, which the `AsyncFn`
+                // traits expressly allow the user to write. To fix this correctly,
+                // we'd need to instantiate trait bounds before we get to selection,
+                // like the new trait solver does.
                 let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
+                let placeholder_output_ty = self.infcx.enter_forall_and_leak_universe(sig.output());
                 nested.push(obligation.with(
                     tcx,
-                    sig.map_bound(|sig| {
-                        ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()])
-                    }),
+                    ty::TraitRef::new(tcx, future_trait_def_id, [placeholder_output_ty]),
                 ));
+
                 (trait_ref, Ty::from_closure_kind(tcx, ty::ClosureKind::Fn))
             }
             ty::Closure(_, args) => {
@@ -943,14 +951,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         [self_ty, sig.inputs()[0]],
                     )
                 });
+
                 // We must additionally check that the return type impls `Future`.
+                // See FIXME in last branch for why we instantiate the binder eagerly.
                 let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
+                let placeholder_output_ty = self.infcx.enter_forall_and_leak_universe(sig.output());
                 nested.push(obligation.with(
                     tcx,
-                    sig.map_bound(|sig| {
-                        ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()])
-                    }),
+                    ty::TraitRef::new(tcx, future_trait_def_id, [placeholder_output_ty]),
                 ));
+
                 (trait_ref, args.kind_ty())
             }
             _ => bug!("expected callable type for AsyncFn candidate"),