From f0fc4f9acf19c2d35406688ff39106e90edfa979 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 25 Apr 2023 18:59:16 +0000 Subject: Tweak await span --- .../src/traits/error_reporting/suggestions.rs | 86 +++++++++++----------- 1 file changed, 45 insertions(+), 41 deletions(-) (limited to 'compiler/rustc_trait_selection/src') diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index c969e5d4975..9fc16145915 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1583,55 +1583,59 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) { - let span = obligation.cause.span; - - if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() { - let hir = self.tcx.hir(); - if let Some(hir::Node::Expr(expr)) = hir_id.and_then(|hir_id| hir.find(hir_id)) { - // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()` - // and if not maybe suggest doing something else? If we kept the expression around we - // could also check if it is an fn call (very likely) and suggest changing *that*, if - // it is from the local crate. + let hir = self.tcx.hir(); + if let ObligationCauseCode::AwaitableExpr(Some(hir_id)) = obligation.cause.code().peel_derives() + && let hir::Node::Expr(expr) = hir.get(*hir_id) + { + // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()` + // and if not maybe suggest doing something else? If we kept the expression around we + // could also check if it is an fn call (very likely) and suggest changing *that*, if + // it is from the local crate. + + if let hir::Node::Expr(parent_expr) = hir.get_parent(*hir_id) + // Peel off the DesugaringKind from the span + && let Some(desugar_parent_span) = parent_expr.span.parent_callsite() + { err.span_suggestion( - span, + self.tcx.sess.source.shrink_to_hi().to(desugar_parent_span), "remove the `.await`", "", Applicability::MachineApplicable, ); - // FIXME: account for associated `async fn`s. - if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr { - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = - obligation.predicate.kind().skip_binder() + } + // FIXME: account for associated `async fn`s. + if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr { + if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = + obligation.predicate.kind().skip_binder() + { + err.span_label(*span, &format!("this call returns `{}`", pred.self_ty())); + } + if let Some(typeck_results) = &self.typeck_results + && let ty = typeck_results.expr_ty_adjusted(base) + && let ty::FnDef(def_id, _substs) = ty.kind() + && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) = + hir.get_if_local(*def_id) { - err.span_label(*span, &format!("this call returns `{}`", pred.self_ty())); - } - if let Some(typeck_results) = &self.typeck_results - && let ty = typeck_results.expr_ty_adjusted(base) - && let ty::FnDef(def_id, _substs) = ty.kind() - && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) = - hir.get_if_local(*def_id) - { - let msg = format!( - "alternatively, consider making `fn {}` asynchronous", - ident + let msg = format!( + "alternatively, consider making `fn {}` asynchronous", + ident + ); + if vis_span.is_empty() { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &msg, + "async ", + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_verbose( + vis_span.shrink_to_hi(), + &msg, + " async", + Applicability::MaybeIncorrect, ); - if vis_span.is_empty() { - err.span_suggestion_verbose( - span.shrink_to_lo(), - &msg, - "async ", - Applicability::MaybeIncorrect, - ); - } else { - err.span_suggestion_verbose( - vis_span.shrink_to_hi(), - &msg, - " async", - Applicability::MaybeIncorrect, - ); - } } - } + } } } } -- cgit 1.4.1-3-g733a5 From e6077fc1b885c525279d127fd78db4574f735900 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 25 Apr 2023 19:02:55 +0000 Subject: tweak removal span --- .../src/traits/error_reporting/suggestions.rs | 9 ++++++++- tests/ui/async-await/issue-101715.stderr | 12 +++++------- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'compiler/rustc_trait_selection/src') diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 9fc16145915..7e5e266569d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1596,8 +1596,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Peel off the DesugaringKind from the span && let Some(desugar_parent_span) = parent_expr.span.parent_callsite() { + let removal_span = self.tcx + .sess + .source_map() + .span_extend_while(expr.span, char::is_whitespace) + .unwrap_or(expr.span) + .shrink_to_hi() + .to(desugar_parent_span); err.span_suggestion( - self.tcx.sess.source.shrink_to_hi().to(desugar_parent_span), + removal_span, "remove the `.await`", "", Applicability::MachineApplicable, diff --git a/tests/ui/async-await/issue-101715.stderr b/tests/ui/async-await/issue-101715.stderr index 3d0b49b3909..d161fb0c05e 100644 --- a/tests/ui/async-await/issue-101715.stderr +++ b/tests/ui/async-await/issue-101715.stderr @@ -1,13 +1,11 @@ error[E0277]: `()` is not a future --> $DIR/issue-101715.rs:11:10 | -LL | S.very_long_method_name_the_longest_method_name_in_the_whole_universe() - | ____________________________________________________________________________- -LL | | .await - | | ^^^^- - | |__________|___| - | | help: remove the `.await` - | `()` is not a future +LL | .await + | -^^^^^ + | || + | |`()` is not a future + | help: remove the `.await` | = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited -- cgit 1.4.1-3-g733a5 From 6d6c90443182e18fb23c08cd2d97dae701d7b453 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 27 Apr 2023 17:40:55 +0000 Subject: Make async removal span more resilient to macro expansions --- compiler/rustc_ast_lowering/src/errors.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 12 ++------ .../src/traits/error_reporting/suggestions.rs | 14 ++++++---- ...sync_await.b-{closure#0}.generator_resume.0.mir | 2 +- .../incorrect-syntax-suggestions.stderr | 10 +++---- tests/ui/async-await/unnecessary-await.rs | 20 ++++++++++++++ tests/ui/async-await/unnecessary-await.stderr | 32 +++++++++++++++++++++- 7 files changed, 68 insertions(+), 24 deletions(-) (limited to 'compiler/rustc_trait_selection/src') diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 3e9f9b43623..72dc52a6329 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -108,7 +108,7 @@ pub struct BaseExpressionDoubleDot { pub struct AwaitOnlyInAsyncFnAndBlocks { #[primary_span] #[label] - pub dot_await_span: Span, + pub await_kw_span: Span, #[label(ast_lowering_this_not_async)] pub item_span: Option, } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 8a5b26476c2..5e0ab80c6ac 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -185,15 +185,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::AsyncGeneratorKind::Block, |this| this.with_new_scopes(|this| this.lower_block_expr(block)), ), - ExprKind::Await(expr, await_kw_span) => { - let await_kw_span = if expr.span.hi() < await_kw_span.hi() { - *await_kw_span - } else { - // this is a recovered `await expr` - e.span - }; - self.lower_expr_await(await_kw_span, expr) - } + ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr), ExprKind::Closure(box Closure { binder, capture_clause, @@ -710,7 +702,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(hir::GeneratorKind::Async(_)) => {} Some(hir::GeneratorKind::Gen) | None => { self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks { - dot_await_span: await_kw_span, + await_kw_span, item_span: self.current_item, }); } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 7e5e266569d..595f6e0b927 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1592,23 +1592,25 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // could also check if it is an fn call (very likely) and suggest changing *that*, if // it is from the local crate. - if let hir::Node::Expr(parent_expr) = hir.get_parent(*hir_id) - // Peel off the DesugaringKind from the span - && let Some(desugar_parent_span) = parent_expr.span.parent_callsite() + // use nth(1) to skip one layer of desugaring from `IntoIter::into_iter` + if let Some((_, hir::Node::Expr(await_expr))) = hir.parent_iter(*hir_id).nth(1) + && let Some(expr_span) = expr.span.find_ancestor_inside(await_expr.span) { let removal_span = self.tcx .sess .source_map() - .span_extend_while(expr.span, char::is_whitespace) - .unwrap_or(expr.span) + .span_extend_while(expr_span, char::is_whitespace) + .unwrap_or(expr_span) .shrink_to_hi() - .to(desugar_parent_span); + .to(await_expr.span.shrink_to_hi()); err.span_suggestion( removal_span, "remove the `.await`", "", Applicability::MachineApplicable, ); + } else { + err.span_label(obligation.cause.span, "remove the `.await`"); } // FIXME: account for associated `async fn`s. if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr { diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir index cefb8ff3ca9..a9d1477b9fe 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir @@ -12,7 +12,7 @@ _1: GeneratorSavedTy { ty: impl std::future::Future, source_info: SourceInfo { - span: $DIR/async_await.rs:16:8: 16:14 (#10), + span: $DIR/async_await.rs:16:9: 16:14 (#10), scope: scope[0], }, ignore_for_traits: false, diff --git a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index 59630e837b7..7b03e56662a 100644 --- a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -143,7 +143,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks LL | fn foo9() -> Result<(), ()> { | ---- this is not `async` LL | let _ = await bar(); - | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:57:13 @@ -151,7 +151,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks LL | fn foo10() -> Result<(), ()> { | ----- this is not `async` LL | let _ = await? bar(); - | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:66:14 @@ -159,7 +159,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks LL | fn foo12() -> Result<(), ()> { | ----- this is not `async` LL | let _ = (await bar())?; - | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:71:19 @@ -215,7 +215,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks LL | fn foo() -> Result<(), ()> { | --- this is not `async` LL | let _ = await!(bar())?; - | ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:121:17 @@ -223,7 +223,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks LL | let foo = || { | -- this is not `async` LL | let _ = await!(bar())?; - | ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error: aborting due to 33 previous errors diff --git a/tests/ui/async-await/unnecessary-await.rs b/tests/ui/async-await/unnecessary-await.rs index 24673777b80..cd1e2871432 100644 --- a/tests/ui/async-await/unnecessary-await.rs +++ b/tests/ui/async-await/unnecessary-await.rs @@ -11,4 +11,24 @@ async fn baz() -> std::io::Result<()> { std::io::Result::Ok(()) } +macro_rules! e { + () => { + () + }; +} + +macro_rules! f { + ($expr:expr) => { + $expr.await + //~^ ERROR `()` is not a future + }; +} + +async fn with_macros() { + e!().await; + //~^ ERROR `()` is not a future + + f!(()); +} + fn main() {} diff --git a/tests/ui/async-await/unnecessary-await.stderr b/tests/ui/async-await/unnecessary-await.stderr index f1b358ed68a..9a2a035b2dd 100644 --- a/tests/ui/async-await/unnecessary-await.stderr +++ b/tests/ui/async-await/unnecessary-await.stderr @@ -19,6 +19,36 @@ help: alternatively, consider making `fn boo` asynchronous LL | async fn boo() {} | +++++ -error: aborting due to previous error +error[E0277]: `()` is not a future + --> $DIR/unnecessary-await.rs:28:10 + | +LL | e!().await; + | -^^^^^ + | || + | |`()` is not a future + | help: remove the `.await` + | + = help: the trait `Future` is not implemented for `()` + = note: () must be a future or must implement `IntoFuture` to be awaited + = note: required for `()` to implement `IntoFuture` + +error[E0277]: `()` is not a future + --> $DIR/unnecessary-await.rs:22:15 + | +LL | $expr.await + | ^^^^^ + | | + | `()` is not a future + | remove the `.await` +... +LL | f!(()); + | ------ in this macro invocation + | + = help: the trait `Future` is not implemented for `()` + = note: () must be a future or must implement `IntoFuture` to be awaited + = note: required for `()` to implement `IntoFuture` + = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. -- cgit 1.4.1-3-g733a5