Add a note for ? on future in sync function
This commit is contained in:
parent
fb20e4d3b9
commit
5e8820caaa
@ -3594,52 +3594,64 @@ pub(super) fn suggest_await_before_try(
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
if let Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) =
|
||||
self.tcx.coroutine_kind(obligation.cause.body_id)
|
||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||
|
||||
let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
|
||||
let impls_future = self.type_implements_trait(
|
||||
future_trait,
|
||||
[self.tcx.instantiate_bound_regions_with_erased(self_ty)],
|
||||
obligation.param_env,
|
||||
);
|
||||
if !impls_future.must_apply_modulo_regions() {
|
||||
return;
|
||||
}
|
||||
|
||||
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
|
||||
// `<T as Future>::Output`
|
||||
let projection_ty = trait_pred.map_bound(|trait_pred| {
|
||||
Ty::new_projection(
|
||||
self.tcx,
|
||||
item_def_id,
|
||||
// Future::Output has no args
|
||||
[trait_pred.self_ty()],
|
||||
)
|
||||
});
|
||||
let InferOk { value: projection_ty, .. } =
|
||||
self.at(&obligation.cause, obligation.param_env).normalize(projection_ty);
|
||||
|
||||
debug!(
|
||||
normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty)
|
||||
);
|
||||
let try_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env,
|
||||
trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())),
|
||||
);
|
||||
debug!(try_trait_obligation = ?try_obligation);
|
||||
if self.predicate_may_hold(&try_obligation)
|
||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||
&& snippet.ends_with('?')
|
||||
{
|
||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||
|
||||
let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
|
||||
let impls_future = self.type_implements_trait(
|
||||
future_trait,
|
||||
[self.tcx.instantiate_bound_regions_with_erased(self_ty)],
|
||||
obligation.param_env,
|
||||
);
|
||||
if !impls_future.must_apply_modulo_regions() {
|
||||
return;
|
||||
}
|
||||
|
||||
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
|
||||
// `<T as Future>::Output`
|
||||
let projection_ty = trait_pred.map_bound(|trait_pred| {
|
||||
Ty::new_projection(
|
||||
self.tcx,
|
||||
item_def_id,
|
||||
// Future::Output has no args
|
||||
[trait_pred.self_ty()],
|
||||
)
|
||||
});
|
||||
let InferOk { value: projection_ty, .. } =
|
||||
self.at(&obligation.cause, obligation.param_env).normalize(projection_ty);
|
||||
|
||||
debug!(
|
||||
normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty)
|
||||
);
|
||||
let try_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env,
|
||||
trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())),
|
||||
);
|
||||
debug!(try_trait_obligation = ?try_obligation);
|
||||
if self.predicate_may_hold(&try_obligation)
|
||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||
&& snippet.ends_with('?')
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
|
||||
"consider `await`ing on the `Future`",
|
||||
".await",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
match self.tcx.coroutine_kind(obligation.cause.body_id) {
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
|
||||
err.span_suggestion_verbose(
|
||||
span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
|
||||
"consider `await`ing on the `Future`",
|
||||
".await",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
let mut span: MultiSpan = span.with_lo(span.hi() - BytePos(1)).into();
|
||||
span.push_span_label(
|
||||
self.tcx.def_span(obligation.cause.body_id),
|
||||
"this is not `async`",
|
||||
);
|
||||
err.span_note(
|
||||
span,
|
||||
"this implements `Future` and its output type supports \
|
||||
`?`, but the future cannot be awaited in a synchronous function",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
9
tests/ui/async-await/try-in-sync.rs
Normal file
9
tests/ui/async-await/try-in-sync.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//@ edition: 2021
|
||||
|
||||
async fn foo() -> Result<(), ()> { todo!() }
|
||||
|
||||
fn main() -> Result<(), ()> {
|
||||
foo()?;
|
||||
//~^ ERROR the `?` operator can only be applied to values that implement `Try`
|
||||
Ok(())
|
||||
}
|
18
tests/ui/async-await/try-in-sync.stderr
Normal file
18
tests/ui/async-await/try-in-sync.stderr
Normal file
@ -0,0 +1,18 @@
|
||||
error[E0277]: the `?` operator can only be applied to values that implement `Try`
|
||||
--> $DIR/try-in-sync.rs:6:5
|
||||
|
|
||||
LL | foo()?;
|
||||
| ^^^^^^ the `?` operator cannot be applied to type `impl Future<Output = Result<(), ()>>`
|
||||
|
|
||||
= help: the trait `Try` is not implemented for `impl Future<Output = Result<(), ()>>`
|
||||
note: this implements `Future` and its output type supports `?`, but the future cannot be awaited in a synchronous function
|
||||
--> $DIR/try-in-sync.rs:6:10
|
||||
|
|
||||
LL | fn main() -> Result<(), ()> {
|
||||
| --------------------------- this is not `async`
|
||||
LL | foo()?;
|
||||
| ^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user