Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 5e8820c

Browse files
Add a note for ? on future in sync function
1 parent fb20e4d commit 5e8820c

File tree

3 files changed

+82
-43
lines changed

3 files changed

+82
-43
lines changed

compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs

Lines changed: 55 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3594,52 +3594,64 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
35943594
trait_pred: ty::PolyTraitPredicate<'tcx>,
35953595
span: Span,
35963596
) {
3597-
if let Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) =
3598-
self.tcx.coroutine_kind(obligation.cause.body_id)
3599-
{
3600-
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
3597+
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
36013598

3602-
let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
3603-
let impls_future = self.type_implements_trait(
3604-
future_trait,
3605-
[self.tcx.instantiate_bound_regions_with_erased(self_ty)],
3606-
obligation.param_env,
3607-
);
3608-
if !impls_future.must_apply_modulo_regions() {
3609-
return;
3610-
}
3599+
let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
3600+
let impls_future = self.type_implements_trait(
3601+
future_trait,
3602+
[self.tcx.instantiate_bound_regions_with_erased(self_ty)],
3603+
obligation.param_env,
3604+
);
3605+
if !impls_future.must_apply_modulo_regions() {
3606+
return;
3607+
}
36113608

3612-
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
3613-
// `<T as Future>::Output`
3614-
let projection_ty = trait_pred.map_bound(|trait_pred| {
3615-
Ty::new_projection(
3616-
self.tcx,
3617-
item_def_id,
3618-
// Future::Output has no args
3619-
[trait_pred.self_ty()],
3620-
)
3621-
});
3622-
let InferOk { value: projection_ty, .. } =
3623-
self.at(&obligation.cause, obligation.param_env).normalize(projection_ty);
3609+
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
3610+
// `<T as Future>::Output`
3611+
let projection_ty = trait_pred.map_bound(|trait_pred| {
3612+
Ty::new_projection(
3613+
self.tcx,
3614+
item_def_id,
3615+
// Future::Output has no args
3616+
[trait_pred.self_ty()],
3617+
)
3618+
});
3619+
let InferOk { value: projection_ty, .. } =
3620+
self.at(&obligation.cause, obligation.param_env).normalize(projection_ty);
36243621

3625-
debug!(
3626-
normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty)
3627-
);
3628-
let try_obligation = self.mk_trait_obligation_with_new_self_ty(
3629-
obligation.param_env,
3630-
trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())),
3631-
);
3632-
debug!(try_trait_obligation = ?try_obligation);
3633-
if self.predicate_may_hold(&try_obligation)
3634-
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
3635-
&& snippet.ends_with('?')
3636-
{
3637-
err.span_suggestion_verbose(
3638-
span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
3639-
"consider `await`ing on the `Future`",
3640-
".await",
3641-
Applicability::MaybeIncorrect,
3642-
);
3622+
debug!(
3623+
normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty)
3624+
);
3625+
let try_obligation = self.mk_trait_obligation_with_new_self_ty(
3626+
obligation.param_env,
3627+
trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())),
3628+
);
3629+
debug!(try_trait_obligation = ?try_obligation);
3630+
if self.predicate_may_hold(&try_obligation)
3631+
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
3632+
&& snippet.ends_with('?')
3633+
{
3634+
match self.tcx.coroutine_kind(obligation.cause.body_id) {
3635+
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
3636+
err.span_suggestion_verbose(
3637+
span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
3638+
"consider `await`ing on the `Future`",
3639+
".await",
3640+
Applicability::MaybeIncorrect,
3641+
);
3642+
}
3643+
_ => {
3644+
let mut span: MultiSpan = span.with_lo(span.hi() - BytePos(1)).into();
3645+
span.push_span_label(
3646+
self.tcx.def_span(obligation.cause.body_id),
3647+
"this is not `async`",
3648+
);
3649+
err.span_note(
3650+
span,
3651+
"this implements `Future` and its output type supports \
3652+
`?`, but the future cannot be awaited in a synchronous function",
3653+
);
3654+
}
36433655
}
36443656
}
36453657
}

tests/ui/async-await/try-in-sync.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//@ edition: 2021
2+
3+
async fn foo() -> Result<(), ()> { todo!() }
4+
5+
fn main() -> Result<(), ()> {
6+
foo()?;
7+
//~^ ERROR the `?` operator can only be applied to values that implement `Try`
8+
Ok(())
9+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0277]: the `?` operator can only be applied to values that implement `Try`
2+
--> $DIR/try-in-sync.rs:6:5
3+
|
4+
LL | foo()?;
5+
| ^^^^^^ the `?` operator cannot be applied to type `impl Future<Output = Result<(), ()>>`
6+
|
7+
= help: the trait `Try` is not implemented for `impl Future<Output = Result<(), ()>>`
8+
note: this implements `Future` and its output type supports `?`, but the future cannot be awaited in a synchronous function
9+
--> $DIR/try-in-sync.rs:6:10
10+
|
11+
LL | fn main() -> Result<(), ()> {
12+
| --------------------------- this is not `async`
13+
LL | foo()?;
14+
| ^
15+
16+
error: aborting due to 1 previous error
17+
18+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)