Skip to content

Commit 1b262b8

Browse files
authored
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.
2 parents 9ecda8d + 6d6c904 commit 1b262b8

File tree

113 files changed

+593
-806
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+593
-806
lines changed

compiler/rustc_ast/src/ast.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1430,8 +1430,8 @@ pub enum ExprKind {
14301430
/// The async block used to have a `NodeId`, which was removed in favor of
14311431
/// using the parent `NodeId` of the parent `Expr`.
14321432
Async(CaptureBy, P<Block>),
1433-
/// An await expression (`my_future.await`).
1434-
Await(P<Expr>),
1433+
/// An await expression (`my_future.await`). Span is of await keyword.
1434+
Await(P<Expr>, Span),
14351435

14361436
/// A try block (`try { ... }`).
14371437
TryBlock(P<Block>),

compiler/rustc_ast/src/mut_visit.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1415,7 +1415,10 @@ pub fn noop_visit_expr<T: MutVisitor>(
14151415
ExprKind::Async(_capture_by, body) => {
14161416
vis.visit_block(body);
14171417
}
1418-
ExprKind::Await(expr) => vis.visit_expr(expr),
1418+
ExprKind::Await(expr, await_kw_span) => {
1419+
vis.visit_expr(expr);
1420+
vis.visit_span(await_kw_span);
1421+
}
14191422
ExprKind::Assign(el, er, _) => {
14201423
vis.visit_expr(el);
14211424
vis.visit_expr(er);

compiler/rustc_ast/src/util/parser.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
388388
// X { y: 1 } + X { y: 2 }
389389
contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)
390390
}
391-
ast::ExprKind::Await(x)
391+
ast::ExprKind::Await(x, _)
392392
| ast::ExprKind::Unary(_, x)
393393
| ast::ExprKind::Cast(x, _)
394394
| ast::ExprKind::Type(x, _)

compiler/rustc_ast/src/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
864864
ExprKind::Async(_, body) => {
865865
visitor.visit_block(body);
866866
}
867-
ExprKind::Await(expr) => visitor.visit_expr(expr),
867+
ExprKind::Await(expr, _) => visitor.visit_expr(expr),
868868
ExprKind::Assign(lhs, rhs, _) => {
869869
visitor.visit_expr(lhs);
870870
visitor.visit_expr(rhs);

compiler/rustc_ast_lowering/src/errors.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ pub struct BaseExpressionDoubleDot {
108108
pub struct AwaitOnlyInAsyncFnAndBlocks {
109109
#[primary_span]
110110
#[label]
111-
pub dot_await_span: Span,
111+
pub await_kw_span: Span,
112112
#[label(ast_lowering_this_not_async)]
113113
pub item_span: Option<Span>,
114114
}

compiler/rustc_ast_lowering/src/expr.rs

+5-19
Original file line numberDiff line numberDiff line change
@@ -185,21 +185,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
185185
hir::AsyncGeneratorKind::Block,
186186
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
187187
),
188-
ExprKind::Await(expr) => {
189-
let dot_await_span = if expr.span.hi() < e.span.hi() {
190-
let span_with_whitespace = self
191-
.tcx
192-
.sess
193-
.source_map()
194-
.span_extend_while(expr.span, char::is_whitespace)
195-
.unwrap_or(expr.span);
196-
span_with_whitespace.shrink_to_hi().with_hi(e.span.hi())
197-
} else {
198-
// this is a recovered `await expr`
199-
e.span
200-
};
201-
self.lower_expr_await(dot_await_span, expr)
202-
}
188+
ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
203189
ExprKind::Closure(box Closure {
204190
binder,
205191
capture_clause,
@@ -710,18 +696,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
710696
/// }
711697
/// }
712698
/// ```
713-
fn lower_expr_await(&mut self, dot_await_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
714-
let full_span = expr.span.to(dot_await_span);
699+
fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
700+
let full_span = expr.span.to(await_kw_span);
715701
match self.generator_kind {
716702
Some(hir::GeneratorKind::Async(_)) => {}
717703
Some(hir::GeneratorKind::Gen) | None => {
718704
self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks {
719-
dot_await_span,
705+
await_kw_span,
720706
item_span: self.current_item,
721707
});
722708
}
723709
}
724-
let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None);
710+
let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, None);
725711
let gen_future_span = self.mark_span_with_reason(
726712
DesugaringKind::Await,
727713
full_span,

compiler/rustc_ast_lowering/src/format.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ fn may_contain_yield_point(e: &ast::Expr) -> bool {
583583

584584
impl Visitor<'_> for MayContainYieldPoint {
585585
fn visit_expr(&mut self, e: &ast::Expr) {
586-
if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
586+
if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind {
587587
self.0 = true;
588588
} else {
589589
visit::walk_expr(self, e);

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ impl<'a> State<'a> {
447447
self.ibox(0);
448448
self.print_block_with_attrs(blk, attrs);
449449
}
450-
ast::ExprKind::Await(expr) => {
450+
ast::ExprKind::Await(expr, _) => {
451451
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
452452
self.word(".await");
453453
}

compiler/rustc_borrowck/messages.ftl

+9
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,15 @@ borrowck_moved_due_to_method_call =
203203
*[false] call
204204
}
205205
206+
borrowck_moved_due_to_await =
207+
{$place_name} {$is_partial ->
208+
[true] partially moved
209+
*[false] moved
210+
} due to this {$is_loop_message ->
211+
[true] await, in previous iteration of loop
212+
*[false] await
213+
}
214+
206215
borrowck_value_moved_here =
207216
value {$is_partial ->
208217
[true] partially moved

compiler/rustc_borrowck/src/diagnostics/mod.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -1085,12 +1085,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
10851085
}
10861086
}
10871087
} else {
1088-
err.subdiagnostic(CaptureReasonLabel::MethodCall {
1089-
fn_call_span,
1090-
place_name: &place_name,
1091-
is_partial,
1092-
is_loop_message,
1093-
});
1088+
if let Some((CallDesugaringKind::Await, _)) = desugaring {
1089+
err.subdiagnostic(CaptureReasonLabel::Await {
1090+
fn_call_span,
1091+
place_name: &place_name,
1092+
is_partial,
1093+
is_loop_message,
1094+
});
1095+
} else {
1096+
err.subdiagnostic(CaptureReasonLabel::MethodCall {
1097+
fn_call_span,
1098+
place_name: &place_name,
1099+
is_partial,
1100+
is_loop_message,
1101+
});
1102+
}
10941103
// Erase and shadow everything that could be passed to the new infcx.
10951104
let ty = moved_place.ty(self.body, tcx).ty;
10961105

compiler/rustc_borrowck/src/session_diagnostics.rs

+8
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,14 @@ pub(crate) enum CaptureReasonLabel<'a> {
338338
is_partial: bool,
339339
is_loop_message: bool,
340340
},
341+
#[label(borrowck_moved_due_to_await)]
342+
Await {
343+
#[primary_span]
344+
fn_call_span: Span,
345+
place_name: &'a str,
346+
is_partial: bool,
347+
is_loop_message: bool,
348+
},
341349
#[label(borrowck_value_moved_here)]
342350
MovedHere {
343351
#[primary_span]

compiler/rustc_builtin_macros/src/assert/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
288288
ExprKind::Assign(_, _, _)
289289
| ExprKind::AssignOp(_, _, _)
290290
| ExprKind::Async(_, _)
291-
| ExprKind::Await(_)
291+
| ExprKind::Await(_, _)
292292
| ExprKind::Block(_, _)
293293
| ExprKind::Break(_, _)
294294
| ExprKind::Closure(_)

compiler/rustc_const_eval/src/transform/check_consts/ops.rs

+3
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
184184
CallDesugaringKind::TryBlockFromOutput => {
185185
error!("`try` block cannot convert `{}` to the result in {}s")
186186
}
187+
CallDesugaringKind::Await => {
188+
error!("cannot convert `{}` into a future in {}s")
189+
}
187190
};
188191

189192
diag_trait(&mut err, self_ty, kind.trait_def_id(tcx));

compiler/rustc_middle/src/util/call_kind.rs

+5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ pub enum CallDesugaringKind {
1919
QuestionFromResidual,
2020
/// try { ..; x } calls type_of(x)::from_output(x)
2121
TryBlockFromOutput,
22+
/// `.await` calls `IntoFuture::into_future`
23+
Await,
2224
}
2325

2426
impl CallDesugaringKind {
@@ -29,6 +31,7 @@ impl CallDesugaringKind {
2931
tcx.require_lang_item(LangItem::Try, None)
3032
}
3133
Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(),
34+
Self::Await => tcx.get_diagnostic_item(sym::IntoFuture).unwrap(),
3235
}
3336
}
3437
}
@@ -129,6 +132,8 @@ pub fn call_kind<'tcx>(
129132
&& fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock)
130133
{
131134
Some((CallDesugaringKind::TryBlockFromOutput, method_substs.type_at(0)))
135+
} else if fn_call_span.is_desugaring(DesugaringKind::Await) {
136+
Some((CallDesugaringKind::Await, method_substs.type_at(0)))
132137
} else {
133138
None
134139
};

compiler/rustc_parse/src/parser/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1646,7 +1646,7 @@ impl<'a> Parser<'a> {
16461646
// Avoid knock-down errors as we don't know whether to interpret this as `foo().await?`
16471647
// or `foo()?.await` (the very reason we went with postfix syntax 😅).
16481648
ExprKind::Try(_) => ExprKind::Err,
1649-
_ => ExprKind::Await(expr),
1649+
_ => ExprKind::Await(expr, await_sp),
16501650
};
16511651
let expr = self.mk_expr(lo.to(sp), kind);
16521652
self.maybe_recover_from_bad_qpath(expr)

compiler/rustc_parse/src/parser/expr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -859,7 +859,7 @@ impl<'a> Parser<'a> {
859859
ExprKind::Field(_, _) => "a field access",
860860
ExprKind::MethodCall(_) => "a method call",
861861
ExprKind::Call(_, _) => "a function call",
862-
ExprKind::Await(_) => "`.await`",
862+
ExprKind::Await(_, _) => "`.await`",
863863
ExprKind::Err => return Ok(with_postfix),
864864
_ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
865865
}
@@ -3252,7 +3252,7 @@ impl<'a> Parser<'a> {
32523252

32533253
fn mk_await_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> {
32543254
let span = lo.to(self.prev_token.span);
3255-
let await_expr = self.mk_expr(span, ExprKind::Await(self_arg));
3255+
let await_expr = self.mk_expr(span, ExprKind::Await(self_arg, self.prev_token.span));
32563256
self.recover_from_await_method_call();
32573257
await_expr
32583258
}

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ symbols! {
207207
Input,
208208
Into,
209209
IntoDiagnostic,
210+
IntoFuture,
210211
IntoIterator,
211212
IoRead,
212213
IoWrite,

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

+54-41
Original file line numberDiff line numberDiff line change
@@ -1583,55 +1583,68 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
15831583
}
15841584

15851585
fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) {
1586-
let span = obligation.cause.span;
1587-
1588-
if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() {
1589-
let hir = self.tcx.hir();
1590-
if let Some(hir::Node::Expr(expr)) = hir_id.and_then(|hir_id| hir.find(hir_id)) {
1591-
// FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()`
1592-
// and if not maybe suggest doing something else? If we kept the expression around we
1593-
// could also check if it is an fn call (very likely) and suggest changing *that*, if
1594-
// it is from the local crate.
1586+
let hir = self.tcx.hir();
1587+
if let ObligationCauseCode::AwaitableExpr(Some(hir_id)) = obligation.cause.code().peel_derives()
1588+
&& let hir::Node::Expr(expr) = hir.get(*hir_id)
1589+
{
1590+
// FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()`
1591+
// and if not maybe suggest doing something else? If we kept the expression around we
1592+
// could also check if it is an fn call (very likely) and suggest changing *that*, if
1593+
// it is from the local crate.
1594+
1595+
// use nth(1) to skip one layer of desugaring from `IntoIter::into_iter`
1596+
if let Some((_, hir::Node::Expr(await_expr))) = hir.parent_iter(*hir_id).nth(1)
1597+
&& let Some(expr_span) = expr.span.find_ancestor_inside(await_expr.span)
1598+
{
1599+
let removal_span = self.tcx
1600+
.sess
1601+
.source_map()
1602+
.span_extend_while(expr_span, char::is_whitespace)
1603+
.unwrap_or(expr_span)
1604+
.shrink_to_hi()
1605+
.to(await_expr.span.shrink_to_hi());
15951606
err.span_suggestion(
1596-
span,
1607+
removal_span,
15971608
"remove the `.await`",
15981609
"",
15991610
Applicability::MachineApplicable,
16001611
);
1601-
// FIXME: account for associated `async fn`s.
1602-
if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr {
1603-
if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) =
1604-
obligation.predicate.kind().skip_binder()
1612+
} else {
1613+
err.span_label(obligation.cause.span, "remove the `.await`");
1614+
}
1615+
// FIXME: account for associated `async fn`s.
1616+
if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr {
1617+
if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) =
1618+
obligation.predicate.kind().skip_binder()
1619+
{
1620+
err.span_label(*span, &format!("this call returns `{}`", pred.self_ty()));
1621+
}
1622+
if let Some(typeck_results) = &self.typeck_results
1623+
&& let ty = typeck_results.expr_ty_adjusted(base)
1624+
&& let ty::FnDef(def_id, _substs) = ty.kind()
1625+
&& let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
1626+
hir.get_if_local(*def_id)
16051627
{
1606-
err.span_label(*span, &format!("this call returns `{}`", pred.self_ty()));
1607-
}
1608-
if let Some(typeck_results) = &self.typeck_results
1609-
&& let ty = typeck_results.expr_ty_adjusted(base)
1610-
&& let ty::FnDef(def_id, _substs) = ty.kind()
1611-
&& let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
1612-
hir.get_if_local(*def_id)
1613-
{
1614-
let msg = format!(
1615-
"alternatively, consider making `fn {}` asynchronous",
1616-
ident
1628+
let msg = format!(
1629+
"alternatively, consider making `fn {}` asynchronous",
1630+
ident
1631+
);
1632+
if vis_span.is_empty() {
1633+
err.span_suggestion_verbose(
1634+
span.shrink_to_lo(),
1635+
&msg,
1636+
"async ",
1637+
Applicability::MaybeIncorrect,
1638+
);
1639+
} else {
1640+
err.span_suggestion_verbose(
1641+
vis_span.shrink_to_hi(),
1642+
&msg,
1643+
" async",
1644+
Applicability::MaybeIncorrect,
16171645
);
1618-
if vis_span.is_empty() {
1619-
err.span_suggestion_verbose(
1620-
span.shrink_to_lo(),
1621-
&msg,
1622-
"async ",
1623-
Applicability::MaybeIncorrect,
1624-
);
1625-
} else {
1626-
err.span_suggestion_verbose(
1627-
vis_span.shrink_to_hi(),
1628-
&msg,
1629-
" async",
1630-
Applicability::MaybeIncorrect,
1631-
);
1632-
}
16331646
}
1634-
}
1647+
}
16351648
}
16361649
}
16371650
}

library/core/src/future/into_future.rs

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ use crate::future::Future;
9999
/// }
100100
/// ```
101101
#[stable(feature = "into_future", since = "1.64.0")]
102+
#[rustc_diagnostic_item = "IntoFuture"]
102103
pub trait IntoFuture {
103104
/// The output that the future will produce on completion.
104105
#[stable(feature = "into_future", since = "1.64.0")]

src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ fn ident_difference_expr_with_base_location(
577577
| (AssignOp(_, _, _), AssignOp(_, _, _))
578578
| (Assign(_, _, _), Assign(_, _, _))
579579
| (TryBlock(_), TryBlock(_))
580-
| (Await(_), Await(_))
580+
| (Await(_, _), Await(_, _))
581581
| (Async(_, _), Async(_, _))
582582
| (Block(_, _), Block(_, _))
583583
| (Closure(_), Closure(_))

src/tools/clippy/clippy_utils/src/ast_utils.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
143143
(Paren(l), _) => eq_expr(l, r),
144144
(_, Paren(r)) => eq_expr(l, r),
145145
(Err, Err) => true,
146-
(Try(l), Try(r)) | (Await(l), Await(r)) => eq_expr(l, r),
146+
(Try(l), Try(r)) | (Await(l, _), Await(r, _)) => eq_expr(l, r),
147147
(Array(l), Array(r)) => over(l, r, |l, r| eq_expr(l, r)),
148148
(Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)),
149149
(Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value),

0 commit comments

Comments
 (0)