Keep track of the start of the argument block of a closure

This commit is contained in:
Sarthak Singh 2022-11-09 20:39:28 +05:30
parent 872631d0f0
commit 8f705e2425
15 changed files with 53 additions and 29 deletions

View File

@ -1280,8 +1280,10 @@ pub struct Closure {
pub movability: Movability, pub movability: Movability,
pub fn_decl: P<FnDecl>, pub fn_decl: P<FnDecl>,
pub body: P<Expr>, pub body: P<Expr>,
/// The span of the argument block `|...|`. /// The span of the declaration block: 'move |...| -> ...'
pub fn_decl_span: Span, pub fn_decl_span: Span,
/// The span of the argument block `|...|`
pub fn_arg_span: Span,
} }
/// Limit types of a range (inclusive or exclusive) /// Limit types of a range (inclusive or exclusive)

View File

@ -1371,6 +1371,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
fn_decl, fn_decl,
body, body,
fn_decl_span, fn_decl_span,
fn_arg_span: _,
}) => { }) => {
vis.visit_closure_binder(binder); vis.visit_closure_binder(binder);
vis.visit_asyncness(asyncness); vis.visit_asyncness(asyncness);

View File

@ -840,6 +840,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
fn_decl, fn_decl,
body, body,
fn_decl_span: _, fn_decl_span: _,
fn_arg_span: _,
}) => { }) => {
visitor.visit_fn(FnKind::Closure(binder, fn_decl, body), expression.span, expression.id) visitor.visit_fn(FnKind::Closure(binder, fn_decl, body), expression.span, expression.id)
} }

View File

@ -176,6 +176,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl, fn_decl,
body, body,
fn_decl_span, fn_decl_span,
fn_arg_span,
}) => { }) => {
if let Async::Yes { closure_id, .. } = asyncness { if let Async::Yes { closure_id, .. } = asyncness {
self.lower_expr_async_closure( self.lower_expr_async_closure(
@ -186,6 +187,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl, fn_decl,
body, body,
*fn_decl_span, *fn_decl_span,
*fn_arg_span,
) )
} else { } else {
self.lower_expr_closure( self.lower_expr_closure(
@ -196,6 +198,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl, fn_decl,
body, body,
*fn_decl_span, *fn_decl_span,
*fn_arg_span,
) )
} }
} }
@ -639,6 +642,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl, fn_decl,
body, body,
fn_decl_span: self.lower_span(span), fn_decl_span: self.lower_span(span),
fn_arg_span: None,
movability: Some(hir::Movability::Static), movability: Some(hir::Movability::Static),
}); });
@ -887,6 +891,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
decl: &FnDecl, decl: &FnDecl,
body: &Expr, body: &Expr,
fn_decl_span: Span, fn_decl_span: Span,
fn_arg_span: Span,
) -> hir::ExprKind<'hir> { ) -> hir::ExprKind<'hir> {
let (binder_clause, generic_params) = self.lower_closure_binder(binder); let (binder_clause, generic_params) = self.lower_closure_binder(binder);
@ -917,6 +922,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl, fn_decl,
body: body_id, body: body_id,
fn_decl_span: self.lower_span(fn_decl_span), fn_decl_span: self.lower_span(fn_decl_span),
fn_arg_span: Some(self.lower_span(fn_arg_span)),
movability: generator_option, movability: generator_option,
}); });
@ -973,6 +979,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
decl: &FnDecl, decl: &FnDecl,
body: &Expr, body: &Expr,
fn_decl_span: Span, fn_decl_span: Span,
fn_arg_span: Span,
) -> hir::ExprKind<'hir> { ) -> hir::ExprKind<'hir> {
if let &ClosureBinder::For { span, .. } = binder { if let &ClosureBinder::For { span, .. } = binder {
self.tcx.sess.emit_err(NotSupportedForLifetimeBinderAsyncClosure { span }); self.tcx.sess.emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
@ -1027,6 +1034,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl, fn_decl,
body, body,
fn_decl_span: self.lower_span(fn_decl_span), fn_decl_span: self.lower_span(fn_decl_span),
fn_arg_span: Some(self.lower_span(fn_arg_span)),
movability: None, movability: None,
}); });
hir::ExprKind::Closure(c) hir::ExprKind::Closure(c)

View File

@ -409,6 +409,7 @@ impl<'a> State<'a> {
ref fn_decl, ref fn_decl,
ref body, ref body,
fn_decl_span: _, fn_decl_span: _,
fn_arg_span: _,
}) => { }) => {
self.print_closure_binder(binder); self.print_closure_binder(binder);
self.print_movability(movability); self.print_movability(movability);

View File

@ -539,6 +539,9 @@ impl<'a> ExtCtxt<'a> {
fn_decl, fn_decl,
body, body,
fn_decl_span: span, fn_decl_span: span,
// FIXME(SarthakSingh31): This points to the start of the declaration block and
// not the span of the argument block.
fn_arg_span: span,
})), })),
) )
} }

View File

@ -928,7 +928,10 @@ pub struct Closure<'hir> {
pub bound_generic_params: &'hir [GenericParam<'hir>], pub bound_generic_params: &'hir [GenericParam<'hir>],
pub fn_decl: &'hir FnDecl<'hir>, pub fn_decl: &'hir FnDecl<'hir>,
pub body: BodyId, pub body: BodyId,
/// The span of the declaration block: 'move |...| -> ...'
pub fn_decl_span: Span, pub fn_decl_span: Span,
/// The span of the argument block `|...|`
pub fn_arg_span: Option<Span>,
pub movability: Option<Movability>, pub movability: Option<Movability>,
} }

View File

@ -740,6 +740,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
body, body,
capture_clause: _, capture_clause: _,
fn_decl_span: _, fn_decl_span: _,
fn_arg_span: _,
movability: _, movability: _,
}) => { }) => {
walk_list!(visitor, visit_generic_param, bound_generic_params); walk_list!(visitor, visit_generic_param, bound_generic_params);

View File

@ -1480,6 +1480,7 @@ impl<'a> State<'a> {
fn_decl, fn_decl,
body, body,
fn_decl_span: _, fn_decl_span: _,
fn_arg_span: _,
movability: _, movability: _,
def_id: _, def_id: _,
}) => { }) => {

View File

@ -457,10 +457,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter() .iter()
.map(|ty| ArgKind::from_expected_ty(*ty, None)) .map(|ty| ArgKind::from_expected_ty(*ty, None))
.collect(); .collect();
let (closure_span, found_args) = match self.get_fn_like_arguments(expr_map_node) { let (closure_span, closure_arg_span, found_args) =
Some((sp, args)) => (Some(sp), args), match self.get_fn_like_arguments(expr_map_node) {
None => (None, Vec::new()), Some((sp, arg_sp, args)) => (Some(sp), arg_sp, args),
}; None => (None, None, Vec::new()),
};
let expected_span = let expected_span =
expected_sig.cause_span.unwrap_or_else(|| self.tcx.def_span(expr_def_id)); expected_sig.cause_span.unwrap_or_else(|| self.tcx.def_span(expr_def_id));
self.report_arg_count_mismatch( self.report_arg_count_mismatch(
@ -469,6 +470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_args, expected_args,
found_args, found_args,
true, true,
closure_arg_span,
) )
.emit(); .emit();

View File

@ -1022,7 +1022,7 @@ impl<'hir> Map<'hir> {
.. ..
}) => { }) => {
// Ensure that the returned span has the item's SyntaxContext. // Ensure that the returned span has the item's SyntaxContext.
fn_decl_span.find_ancestor_in_same_ctxt(*span).unwrap_or(*span) fn_decl_span.find_ancestor_inside(*span).unwrap_or(*span)
} }
_ => self.span_with_body(hir_id), _ => self.span_with_body(hir_id),
}; };

View File

@ -2057,7 +2057,7 @@ impl<'a> Parser<'a> {
}; };
let capture_clause = self.parse_capture_clause()?; let capture_clause = self.parse_capture_clause()?;
let fn_decl = self.parse_fn_block_decl()?; let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
let decl_hi = self.prev_token.span; let decl_hi = self.prev_token.span;
let mut body = match fn_decl.output { let mut body = match fn_decl.output {
FnRetTy::Default(_) => { FnRetTy::Default(_) => {
@ -2098,6 +2098,7 @@ impl<'a> Parser<'a> {
fn_decl, fn_decl,
body, body,
fn_decl_span: lo.to(decl_hi), fn_decl_span: lo.to(decl_hi),
fn_arg_span,
})), })),
); );
@ -2126,7 +2127,9 @@ impl<'a> Parser<'a> {
} }
/// Parses the `|arg, arg|` header of a closure. /// Parses the `|arg, arg|` header of a closure.
fn parse_fn_block_decl(&mut self) -> PResult<'a, P<FnDecl>> { fn parse_fn_block_decl(&mut self) -> PResult<'a, (P<FnDecl>, Span)> {
let arg_start = self.token.span.lo();
let inputs = if self.eat(&token::OrOr) { let inputs = if self.eat(&token::OrOr) {
Vec::new() Vec::new()
} else { } else {
@ -2142,10 +2145,11 @@ impl<'a> Parser<'a> {
self.expect_or()?; self.expect_or()?;
args args
}; };
let arg_span = self.prev_token.span.with_lo(arg_start);
let output = let output =
self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?; self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?;
Ok(P(FnDecl { inputs, output })) Ok((P(FnDecl { inputs, output }), arg_span))
} }
/// Parses a parameter in a closure header (e.g., `|arg, arg|`). /// Parses a parameter in a closure header (e.g., `|arg, arg|`).

View File

@ -70,7 +70,7 @@ pub trait InferCtxtExt<'tcx> {
/// returns a span and `ArgKind` information that describes the /// returns a span and `ArgKind` information that describes the
/// arguments it expects. This can be supplied to /// arguments it expects. This can be supplied to
/// `report_arg_count_mismatch`. /// `report_arg_count_mismatch`.
fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)>; fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)>;
/// Reports an error when the number of arguments needed by a /// Reports an error when the number of arguments needed by a
/// trait match doesn't match the number that the expression /// trait match doesn't match the number that the expression
@ -82,6 +82,7 @@ pub trait InferCtxtExt<'tcx> {
expected_args: Vec<ArgKind>, expected_args: Vec<ArgKind>,
found_args: Vec<ArgKind>, found_args: Vec<ArgKind>,
is_closure: bool, is_closure: bool,
closure_pipe_span: Option<Span>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
/// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
@ -134,15 +135,16 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
/// returns a span and `ArgKind` information that describes the /// returns a span and `ArgKind` information that describes the
/// arguments it expects. This can be supplied to /// arguments it expects. This can be supplied to
/// `report_arg_count_mismatch`. /// `report_arg_count_mismatch`.
fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)> { fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)> {
let sm = self.tcx.sess.source_map(); let sm = self.tcx.sess.source_map();
let hir = self.tcx.hir(); let hir = self.tcx.hir();
Some(match node { Some(match node {
Node::Expr(&hir::Expr { Node::Expr(&hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }), kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, fn_arg_span, .. }),
.. ..
}) => ( }) => (
fn_decl_span, fn_decl_span,
fn_arg_span,
hir.body(body) hir.body(body)
.params .params
.iter() .iter()
@ -173,6 +175,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
kind: hir::TraitItemKind::Fn(ref sig, _), .. kind: hir::TraitItemKind::Fn(ref sig, _), ..
}) => ( }) => (
sig.span, sig.span,
None,
sig.decl sig.decl
.inputs .inputs
.iter() .iter()
@ -187,7 +190,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
), ),
Node::Ctor(ref variant_data) => { Node::Ctor(ref variant_data) => {
let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
(span, vec![ArgKind::empty(); variant_data.fields().len()]) (span, None, vec![ArgKind::empty(); variant_data.fields().len()])
} }
_ => panic!("non-FnLike node found: {:?}", node), _ => panic!("non-FnLike node found: {:?}", node),
}) })
@ -203,6 +206,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
expected_args: Vec<ArgKind>, expected_args: Vec<ArgKind>,
found_args: Vec<ArgKind>, found_args: Vec<ArgKind>,
is_closure: bool, is_closure: bool,
closure_arg_span: Option<Span>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let kind = if is_closure { "closure" } else { "function" }; let kind = if is_closure { "closure" } else { "function" };
@ -240,24 +244,13 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
if let Some(found_span) = found_span { if let Some(found_span) = found_span {
err.span_label(found_span, format!("takes {}", found_str)); err.span_label(found_span, format!("takes {}", found_str));
// move |_| { ... }
// ^^^^^^^^-- def_span
//
// move |_| { ... }
// ^^^^^-- prefix
let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span);
// move |_| { ... }
// ^^^-- pipe_span
let pipe_span =
if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span };
// Suggest to take and ignore the arguments with expected_args_length `_`s if // Suggest to take and ignore the arguments with expected_args_length `_`s if
// found arguments is empty (assume the user just wants to ignore args in this case). // found arguments is empty (assume the user just wants to ignore args in this case).
// For example, if `expected_args_length` is 2, suggest `|_, _|`. // For example, if `expected_args_length` is 2, suggest `|_, _|`.
if found_args.is_empty() && is_closure { if found_args.is_empty() && is_closure {
let underscores = vec!["_"; expected_args.len()].join(", "); let underscores = vec!["_"; expected_args.len()].join(", ");
err.span_suggestion_verbose( err.span_suggestion_verbose(
pipe_span, closure_arg_span.unwrap_or(found_span),
&format!( &format!(
"consider changing the closure to take and ignore the expected argument{}", "consider changing the closure to take and ignore the expected argument{}",
pluralize!(expected_args.len()) pluralize!(expected_args.len())
@ -1251,13 +1244,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
obligation.cause.code(), obligation.cause.code(),
) )
} else { } else {
let (closure_span, found) = found_did let (closure_span, closure_arg_span, found) = found_did
.and_then(|did| { .and_then(|did| {
let node = self.tcx.hir().get_if_local(did)?; let node = self.tcx.hir().get_if_local(did)?;
let (found_span, found) = self.get_fn_like_arguments(node)?; let (found_span, closure_arg_span, found) =
Some((Some(found_span), found)) self.get_fn_like_arguments(node)?;
Some((Some(found_span), closure_arg_span, found))
}) })
.unwrap_or((found_span, found)); .unwrap_or((found_span, None, found));
self.report_arg_count_mismatch( self.report_arg_count_mismatch(
span, span,
@ -1265,6 +1259,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
expected, expected,
found, found,
found_trait_ty.is_closure(), found_trait_ty.is_closure(),
closure_arg_span,
) )
} }
} }

View File

@ -126,6 +126,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
fn_decl: decl.clone(), fn_decl: decl.clone(),
body: e, body: e,
fn_decl_span: DUMMY_SP, fn_decl_span: DUMMY_SP,
fn_arg_span: DUMMY_SP,
}))) })))
}); });
} }

View File

@ -335,6 +335,7 @@ pub(crate) fn rewrite_last_closure(
ref fn_decl, ref fn_decl,
ref body, ref body,
fn_decl_span: _, fn_decl_span: _,
fn_arg_span: _,
} = **closure; } = **closure;
let body = match body.kind { let body = match body.kind {
ast::ExprKind::Block(ref block, _) ast::ExprKind::Block(ref block, _)