diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2023-05-01 01:09:47 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-05-01 01:09:47 +0200 |
| commit | 1b262b8b5660bc70530f647822b477a8d56e1f4e (patch) | |
| tree | 41299c6d6c037d6b6addf13a984f9220fba45cd0 /compiler | |
| parent | 9ecda8de85ce893cc3fc748ab06be0b8250147a7 (diff) | |
| parent | 6d6c90443182e18fb23c08cd2d97dae701d7b453 (diff) | |
| download | rust-1b262b8b5660bc70530f647822b477a8d56e1f4e.tar.gz rust-1b262b8b5660bc70530f647822b477a8d56e1f4e.zip | |
Rollup merge of #110823 - compiler-errors:tweak-await-span, r=b-naber
Tweak await span to not contain dot Fixes a discrepancy between method calls and await expressions where the latter are desugared to have a span that *contains* the dot (i.e. `.await`) but method call identifiers don't contain the dot. This leads to weird suggestions suggestions in borrowck -- see linked issue. Fixes #110761 This mostly touches a bunch of tests to tighten their `await` span.
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_ast/src/ast.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/mut_visit.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/util/parser.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/visit.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/errors.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/expr.rs | 24 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/format.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_ast_pretty/src/pprust/state/expr.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/messages.ftl | 9 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/diagnostics/mod.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/session_diagnostics.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_builtin_macros/src/assert/context.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/transform/check_consts/ops.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/util/call_kind.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs | 95 |
18 files changed, 115 insertions, 78 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3ed342ce48b..ea04ba4f66e 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1430,8 +1430,8 @@ pub enum ExprKind { /// The async block used to have a `NodeId`, which was removed in favor of /// using the parent `NodeId` of the parent `Expr`. Async(CaptureBy, P<Block>), - /// An await expression (`my_future.await`). - Await(P<Expr>), + /// An await expression (`my_future.await`). Span is of await keyword. + Await(P<Expr>, Span), /// A try block (`try { ... }`). TryBlock(P<Block>), diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 99f1f4bd968..68a4d522993 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1415,7 +1415,10 @@ pub fn noop_visit_expr<T: MutVisitor>( ExprKind::Async(_capture_by, body) => { vis.visit_block(body); } - ExprKind::Await(expr) => vis.visit_expr(expr), + ExprKind::Await(expr, await_kw_span) => { + vis.visit_expr(expr); + vis.visit_span(await_kw_span); + } ExprKind::Assign(el, er, _) => { vis.visit_expr(el); vis.visit_expr(er); diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 24b4bd8623f..64ae904513c 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -388,7 +388,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { // X { y: 1 } + X { y: 2 } contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs) } - ast::ExprKind::Await(x) + ast::ExprKind::Await(x, _) | ast::ExprKind::Unary(_, x) | ast::ExprKind::Cast(x, _) | ast::ExprKind::Type(x, _) diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 8a6b5d5c905..1526ffa0b03 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -864,7 +864,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Async(_, body) => { visitor.visit_block(body); } - ExprKind::Await(expr) => visitor.visit_expr(expr), + ExprKind::Await(expr, _) => visitor.visit_expr(expr), ExprKind::Assign(lhs, rhs, _) => { visitor.visit_expr(lhs); visitor.visit_expr(rhs); 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<Span>, } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 7a0a7da9695..5e0ab80c6ac 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -185,21 +185,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::AsyncGeneratorKind::Block, |this| this.with_new_scopes(|this| this.lower_block_expr(block)), ), - ExprKind::Await(expr) => { - let dot_await_span = if expr.span.hi() < e.span.hi() { - let span_with_whitespace = self - .tcx - .sess - .source_map() - .span_extend_while(expr.span, char::is_whitespace) - .unwrap_or(expr.span); - span_with_whitespace.shrink_to_hi().with_hi(e.span.hi()) - } else { - // this is a recovered `await expr` - e.span - }; - self.lower_expr_await(dot_await_span, expr) - } + ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr), ExprKind::Closure(box Closure { binder, capture_clause, @@ -710,18 +696,18 @@ impl<'hir> LoweringContext<'_, 'hir> { /// } /// } /// ``` - fn lower_expr_await(&mut self, dot_await_span: Span, expr: &Expr) -> hir::ExprKind<'hir> { - let full_span = expr.span.to(dot_await_span); + fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> { + let full_span = expr.span.to(await_kw_span); match self.generator_kind { Some(hir::GeneratorKind::Async(_)) => {} Some(hir::GeneratorKind::Gen) | None => { self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks { - dot_await_span, + await_kw_span, item_span: self.current_item, }); } } - let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None); + let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, None); let gen_future_span = self.mark_span_with_reason( DesugaringKind::Await, full_span, diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index c081162ea14..9b295339d94 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -583,7 +583,7 @@ fn may_contain_yield_point(e: &ast::Expr) -> bool { impl Visitor<'_> for MayContainYieldPoint { fn visit_expr(&mut self, e: &ast::Expr) { - if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind { + if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind { self.0 = true; } else { visit::walk_expr(self, e); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index aeb0c762020..bac8d21eb7a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -447,7 +447,7 @@ impl<'a> State<'a> { self.ibox(0); self.print_block_with_attrs(blk, attrs); } - ast::ExprKind::Await(expr) => { + ast::ExprKind::Await(expr, _) => { self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); self.word(".await"); } diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index 0b8123c9703..4a616dc2464 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -203,6 +203,15 @@ borrowck_moved_due_to_method_call = *[false] call } +borrowck_moved_due_to_await = + {$place_name} {$is_partial -> + [true] partially moved + *[false] moved + } due to this {$is_loop_message -> + [true] await, in previous iteration of loop + *[false] await + } + borrowck_value_moved_here = value {$is_partial -> [true] partially moved diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 4243ec214b0..a780255725e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1085,12 +1085,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } } else { - err.subdiagnostic(CaptureReasonLabel::MethodCall { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }); + if let Some((CallDesugaringKind::Await, _)) = desugaring { + err.subdiagnostic(CaptureReasonLabel::Await { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); + } else { + err.subdiagnostic(CaptureReasonLabel::MethodCall { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); + } // Erase and shadow everything that could be passed to the new infcx. let ty = moved_place.ty(self.body, tcx).ty; diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index bb95101845f..fceae5bb3ff 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -338,6 +338,14 @@ pub(crate) enum CaptureReasonLabel<'a> { is_partial: bool, is_loop_message: bool, }, + #[label(borrowck_moved_due_to_await)] + Await { + #[primary_span] + fn_call_span: Span, + place_name: &'a str, + is_partial: bool, + is_loop_message: bool, + }, #[label(borrowck_value_moved_here)] MovedHere { #[primary_span] diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 090e00616fb..bd3f148c9a7 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -288,7 +288,7 @@ impl<'cx, 'a> Context<'cx, 'a> { ExprKind::Assign(_, _, _) | ExprKind::AssignOp(_, _, _) | ExprKind::Async(_, _) - | ExprKind::Await(_) + | ExprKind::Await(_, _) | ExprKind::Block(_, _) | ExprKind::Break(_, _) | ExprKind::Closure(_) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 4fb66854571..e3d39091a74 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -184,6 +184,9 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { CallDesugaringKind::TryBlockFromOutput => { error!("`try` block cannot convert `{}` to the result in {}s") } + CallDesugaringKind::Await => { + error!("cannot convert `{}` into a future in {}s") + } }; diag_trait(&mut err, self_ty, kind.trait_def_id(tcx)); diff --git a/compiler/rustc_middle/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs index 627c84c388c..98d55ea6d40 100644 --- a/compiler/rustc_middle/src/util/call_kind.rs +++ b/compiler/rustc_middle/src/util/call_kind.rs @@ -19,6 +19,8 @@ pub enum CallDesugaringKind { QuestionFromResidual, /// try { ..; x } calls type_of(x)::from_output(x) TryBlockFromOutput, + /// `.await` calls `IntoFuture::into_future` + Await, } impl CallDesugaringKind { @@ -29,6 +31,7 @@ impl CallDesugaringKind { tcx.require_lang_item(LangItem::Try, None) } Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(), + Self::Await => tcx.get_diagnostic_item(sym::IntoFuture).unwrap(), } } } @@ -129,6 +132,8 @@ pub fn call_kind<'tcx>( && fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock) { Some((CallDesugaringKind::TryBlockFromOutput, method_substs.type_at(0))) + } else if fn_call_span.is_desugaring(DesugaringKind::Await) { + Some((CallDesugaringKind::Await, method_substs.type_at(0))) } else { None }; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c14c7f2fa0d..0e041df898c 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1646,7 +1646,7 @@ impl<'a> Parser<'a> { // Avoid knock-down errors as we don't know whether to interpret this as `foo().await?` // or `foo()?.await` (the very reason we went with postfix syntax 😅). ExprKind::Try(_) => ExprKind::Err, - _ => ExprKind::Await(expr), + _ => ExprKind::Await(expr, await_sp), }; let expr = self.mk_expr(lo.to(sp), kind); self.maybe_recover_from_bad_qpath(expr) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 27de9bd7268..bff9de5c652 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -859,7 +859,7 @@ impl<'a> Parser<'a> { ExprKind::Field(_, _) => "a field access", ExprKind::MethodCall(_) => "a method call", ExprKind::Call(_, _) => "a function call", - ExprKind::Await(_) => "`.await`", + ExprKind::Await(_, _) => "`.await`", ExprKind::Err => return Ok(with_postfix), _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"), } @@ -3252,7 +3252,7 @@ impl<'a> Parser<'a> { fn mk_await_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> { let span = lo.to(self.prev_token.span); - let await_expr = self.mk_expr(span, ExprKind::Await(self_arg)); + let await_expr = self.mk_expr(span, ExprKind::Await(self_arg, self.prev_token.span)); self.recover_from_await_method_call(); await_expr } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c2619956219..5bfbff76b4f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -207,6 +207,7 @@ symbols! { Input, Into, IntoDiagnostic, + IntoFuture, IntoIterator, IoRead, IoWrite, 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..595f6e0b927 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,68 @@ 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. + + // 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) + .shrink_to_hi() + .to(await_expr.span.shrink_to_hi()); err.span_suggestion( - span, + removal_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() + } 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 { + 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, - ); - } } - } + } } } } |
