Rollup merge of #98705 - WaffleLapkin:closure_binder, r=cjgillot
Implement `for<>` lifetime binder for closures This PR implements RFC 3216 ([TI](https://github.com/rust-lang/rust/issues/97362)) and allows code like the following: ```rust let _f = for<'a, 'b> |a: &'a A, b: &'b B| -> &'b C { b.c(a) }; // ^^^^^^^^^^^--- new! ``` cc ``@Aaron1011`` ``@cjgillot``
This commit is contained in:
commit
e5a86d7358
@ -1390,7 +1390,7 @@ pub enum ExprKind {
|
||||
/// A closure (e.g., `move |a, b, c| a + b + c`).
|
||||
///
|
||||
/// The final span is the span of the argument block `|...|`.
|
||||
Closure(CaptureBy, Async, Movability, P<FnDecl>, P<Expr>, Span),
|
||||
Closure(ClosureBinder, CaptureBy, Async, Movability, P<FnDecl>, P<Expr>, Span),
|
||||
/// A block (`'label: { ... }`).
|
||||
Block(P<Block>, Option<Label>),
|
||||
/// An async block (`async move { ... }`).
|
||||
@ -1518,6 +1518,31 @@ pub enum Movability {
|
||||
Movable,
|
||||
}
|
||||
|
||||
/// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum ClosureBinder {
|
||||
/// The binder is not present, all closure lifetimes are inferred.
|
||||
NotPresent,
|
||||
/// The binder is present.
|
||||
For {
|
||||
/// Span of the whole `for<>` clause
|
||||
///
|
||||
/// ```text
|
||||
/// for<'a, 'b> |_: &'a (), _: &'b ()| { ... }
|
||||
/// ^^^^^^^^^^^ -- this
|
||||
/// ```
|
||||
span: Span,
|
||||
|
||||
/// Lifetimes in the `for<>` closure
|
||||
///
|
||||
/// ```text
|
||||
/// for<'a, 'b> |_: &'a (), _: &'b ()| { ... }
|
||||
/// ^^^^^^ -- this
|
||||
/// ```
|
||||
generic_params: P<[GenericParam]>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Represents a macro invocation. The `path` indicates which macro
|
||||
/// is being invoked, and the `args` are arguments passed to it.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
|
@ -125,6 +125,10 @@ pub trait MutVisitor: Sized {
|
||||
noop_visit_asyncness(a, self);
|
||||
}
|
||||
|
||||
fn visit_closure_binder(&mut self, b: &mut ClosureBinder) {
|
||||
noop_visit_closure_binder(b, self);
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, b: &mut P<Block>) {
|
||||
noop_visit_block(b, self);
|
||||
}
|
||||
@ -825,6 +829,17 @@ pub fn visit_constness<T: MutVisitor>(constness: &mut Const, vis: &mut T) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis: &mut T) {
|
||||
match binder {
|
||||
ClosureBinder::NotPresent => {}
|
||||
ClosureBinder::For { span: _, generic_params } => {
|
||||
let mut vec = std::mem::take(generic_params).into_vec();
|
||||
vec.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
||||
*generic_params = P::from_vec(vec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) {
|
||||
match asyncness {
|
||||
Async::Yes { span: _, closure_id, return_impl_trait_id } => {
|
||||
@ -1336,7 +1351,8 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||
vis.visit_expr(expr);
|
||||
arms.flat_map_in_place(|arm| vis.flat_map_arm(arm));
|
||||
}
|
||||
ExprKind::Closure(_capture_by, asyncness, _movability, decl, body, span) => {
|
||||
ExprKind::Closure(binder, _capture_by, asyncness, _movability, decl, body, span) => {
|
||||
vis.visit_closure_binder(binder);
|
||||
vis.visit_asyncness(asyncness);
|
||||
vis.visit_fn_decl(decl);
|
||||
vis.visit_expr(body);
|
||||
|
@ -56,14 +56,14 @@ pub enum FnKind<'a> {
|
||||
Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
|
||||
|
||||
/// E.g., `|x, y| body`.
|
||||
Closure(&'a FnDecl, &'a Expr),
|
||||
Closure(&'a ClosureBinder, &'a FnDecl, &'a Expr),
|
||||
}
|
||||
|
||||
impl<'a> FnKind<'a> {
|
||||
pub fn header(&self) -> Option<&'a FnHeader> {
|
||||
match *self {
|
||||
FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
|
||||
FnKind::Closure(_, _) => None,
|
||||
FnKind::Closure(_, _, _) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ impl<'a> FnKind<'a> {
|
||||
pub fn decl(&self) -> &'a FnDecl {
|
||||
match self {
|
||||
FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
|
||||
FnKind::Closure(decl, _) => decl,
|
||||
FnKind::Closure(_, decl, _) => decl,
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,6 +155,9 @@ pub trait Visitor<'ast>: Sized {
|
||||
fn visit_generics(&mut self, g: &'ast Generics) {
|
||||
walk_generics(self, g)
|
||||
}
|
||||
fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) {
|
||||
walk_closure_binder(self, b)
|
||||
}
|
||||
fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
|
||||
walk_where_predicate(self, p)
|
||||
}
|
||||
@ -636,6 +639,15 @@ pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics
|
||||
walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
|
||||
}
|
||||
|
||||
pub fn walk_closure_binder<'a, V: Visitor<'a>>(visitor: &mut V, binder: &'a ClosureBinder) {
|
||||
match binder {
|
||||
ClosureBinder::NotPresent => {}
|
||||
ClosureBinder::For { generic_params, span: _ } => {
|
||||
walk_list!(visitor, visit_generic_param, generic_params)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a WherePredicate) {
|
||||
match *predicate {
|
||||
WherePredicate::BoundPredicate(WhereBoundPredicate {
|
||||
@ -682,7 +694,8 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Spa
|
||||
walk_fn_decl(visitor, &sig.decl);
|
||||
walk_list!(visitor, visit_block, body);
|
||||
}
|
||||
FnKind::Closure(decl, body) => {
|
||||
FnKind::Closure(binder, decl, body) => {
|
||||
visitor.visit_closure_binder(binder);
|
||||
walk_fn_decl(visitor, decl);
|
||||
visitor.visit_expr(body);
|
||||
}
|
||||
@ -856,8 +869,8 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
||||
visitor.visit_expr(subexpression);
|
||||
walk_list!(visitor, visit_arm, arms);
|
||||
}
|
||||
ExprKind::Closure(_, _, _, ref decl, ref body, _decl_span) => {
|
||||
visitor.visit_fn(FnKind::Closure(decl, body), expression.span, expression.id)
|
||||
ExprKind::Closure(ref binder, _, _, _, ref decl, ref body, _decl_span) => {
|
||||
visitor.visit_fn(FnKind::Closure(binder, decl, body), expression.span, expression.id)
|
||||
}
|
||||
ExprKind::Block(ref block, ref opt_label) => {
|
||||
walk_list!(visitor, visit_label, opt_label);
|
||||
|
@ -155,6 +155,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.lower_expr_await(span, expr)
|
||||
}
|
||||
ExprKind::Closure(
|
||||
ref binder,
|
||||
capture_clause,
|
||||
asyncness,
|
||||
movability,
|
||||
@ -164,6 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
) => {
|
||||
if let Async::Yes { closure_id, .. } = asyncness {
|
||||
self.lower_expr_async_closure(
|
||||
binder,
|
||||
capture_clause,
|
||||
e.id,
|
||||
closure_id,
|
||||
@ -173,6 +175,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
)
|
||||
} else {
|
||||
self.lower_expr_closure(
|
||||
binder,
|
||||
capture_clause,
|
||||
e.id,
|
||||
movability,
|
||||
@ -605,13 +608,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
});
|
||||
|
||||
// `static |_task_context| -> <ret_ty> { body }`:
|
||||
let generator_kind = hir::ExprKind::Closure {
|
||||
capture_clause,
|
||||
bound_generic_params: &[],
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: self.lower_span(span),
|
||||
movability: Some(hir::Movability::Static),
|
||||
let generator_kind = {
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
binder: hir::ClosureBinder::Default,
|
||||
capture_clause,
|
||||
bound_generic_params: &[],
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: self.lower_span(span),
|
||||
movability: Some(hir::Movability::Static),
|
||||
});
|
||||
|
||||
hir::ExprKind::Closure(c)
|
||||
};
|
||||
let generator = hir::Expr {
|
||||
hir_id: self.lower_node_id(closure_node_id),
|
||||
@ -831,6 +839,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
fn lower_expr_closure(
|
||||
&mut self,
|
||||
binder: &ClosureBinder,
|
||||
capture_clause: CaptureBy,
|
||||
closure_id: NodeId,
|
||||
movability: Movability,
|
||||
@ -838,7 +847,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
body: &Expr,
|
||||
fn_decl_span: Span,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let (body, generator_option) = self.with_new_scopes(move |this| {
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
let (body_id, generator_option) = self.with_new_scopes(move |this| {
|
||||
let prev = this.current_item;
|
||||
this.current_item = Some(fn_decl_span);
|
||||
let mut generator_kind = None;
|
||||
@ -853,18 +864,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
(body_id, generator_option)
|
||||
});
|
||||
|
||||
self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| {
|
||||
self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
|
||||
// Lower outside new scope to preserve `is_in_loop_condition`.
|
||||
let fn_decl = this.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
|
||||
|
||||
hir::ExprKind::Closure {
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
binder: binder_clause,
|
||||
capture_clause,
|
||||
bound_generic_params,
|
||||
fn_decl,
|
||||
body,
|
||||
body: body_id,
|
||||
fn_decl_span: this.lower_span(fn_decl_span),
|
||||
movability: generator_option,
|
||||
}
|
||||
});
|
||||
|
||||
hir::ExprKind::Closure(c)
|
||||
})
|
||||
}
|
||||
|
||||
@ -906,8 +920,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_closure_binder<'c>(
|
||||
&mut self,
|
||||
binder: &'c ClosureBinder,
|
||||
) -> (hir::ClosureBinder, &'c [GenericParam]) {
|
||||
let (binder, params) = match binder {
|
||||
ClosureBinder::NotPresent => (hir::ClosureBinder::Default, &[][..]),
|
||||
&ClosureBinder::For { span, ref generic_params } => {
|
||||
let span = self.lower_span(span);
|
||||
(hir::ClosureBinder::For { span }, &**generic_params)
|
||||
}
|
||||
};
|
||||
|
||||
(binder, params)
|
||||
}
|
||||
|
||||
fn lower_expr_async_closure(
|
||||
&mut self,
|
||||
binder: &ClosureBinder,
|
||||
capture_clause: CaptureBy,
|
||||
closure_id: NodeId,
|
||||
inner_closure_id: NodeId,
|
||||
@ -915,6 +945,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
body: &Expr,
|
||||
fn_decl_span: Span,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
if let &ClosureBinder::For { span, .. } = binder {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
"`for<...>` binders on `async` closures are not currently supported",
|
||||
);
|
||||
}
|
||||
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
let outer_decl =
|
||||
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
||||
|
||||
@ -952,20 +991,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
body_id
|
||||
});
|
||||
|
||||
self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| {
|
||||
self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
|
||||
// We need to lower the declaration outside the new scope, because we
|
||||
// have to conserve the state of being inside a loop condition for the
|
||||
// closure argument types.
|
||||
let fn_decl = this.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
|
||||
|
||||
hir::ExprKind::Closure {
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
binder: binder_clause,
|
||||
capture_clause,
|
||||
bound_generic_params,
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: this.lower_span(fn_decl_span),
|
||||
movability: None,
|
||||
}
|
||||
});
|
||||
hir::ExprKind::Closure(c)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1597,6 +1597,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
.emit();
|
||||
}
|
||||
|
||||
if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
|
||||
self.check_late_bound_lifetime_defs(generic_params);
|
||||
}
|
||||
|
||||
if let FnKind::Fn(
|
||||
_,
|
||||
_,
|
||||
|
@ -744,6 +744,11 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
||||
"async closures are unstable",
|
||||
"to use an async block, remove the `||`: `async {`"
|
||||
);
|
||||
gate_all!(
|
||||
closure_lifetime_binder,
|
||||
"`for<...>` binders for closures are experimental",
|
||||
"consider removing `for<...>`"
|
||||
);
|
||||
gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
|
||||
gate_all!(generators, "yield syntax is experimental");
|
||||
gate_all!(raw_ref_op, "raw address of syntax is experimental");
|
||||
|
@ -389,6 +389,7 @@ impl<'a> State<'a> {
|
||||
self.bclose(expr.span, empty);
|
||||
}
|
||||
ast::ExprKind::Closure(
|
||||
ref binder,
|
||||
capture_clause,
|
||||
asyncness,
|
||||
movability,
|
||||
@ -396,6 +397,7 @@ impl<'a> State<'a> {
|
||||
ref body,
|
||||
_,
|
||||
) => {
|
||||
self.print_closure_binder(binder);
|
||||
self.print_movability(movability);
|
||||
self.print_asyncness(asyncness);
|
||||
self.print_capture_clause(capture_clause);
|
||||
@ -594,6 +596,15 @@ impl<'a> State<'a> {
|
||||
self.end(); // Close enclosing cbox.
|
||||
}
|
||||
|
||||
fn print_closure_binder(&mut self, binder: &ast::ClosureBinder) {
|
||||
match binder {
|
||||
ast::ClosureBinder::NotPresent => {}
|
||||
ast::ClosureBinder::For { generic_params, .. } => {
|
||||
self.print_formal_generic_params(&generic_params)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_movability(&mut self, movability: ast::Movability) {
|
||||
match movability {
|
||||
ast::Movability::Static => self.word_space("static"),
|
||||
|
@ -891,7 +891,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(local_did);
|
||||
let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
|
||||
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
|
||||
if let hir::ExprKind::Closure { body, fn_decl_span, .. } = expr {
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr {
|
||||
for (captured_place, place) in self
|
||||
.infcx
|
||||
.tcx
|
||||
@ -904,11 +904,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
if target_place == place.as_ref() =>
|
||||
{
|
||||
debug!("closure_span: found captured local {:?}", place);
|
||||
let body = self.infcx.tcx.hir().body(*body);
|
||||
let body = self.infcx.tcx.hir().body(body);
|
||||
let generator_kind = body.generator_kind();
|
||||
|
||||
return Some((
|
||||
*fn_decl_span,
|
||||
fn_decl_span,
|
||||
generator_kind,
|
||||
captured_place.get_capture_kind_span(self.infcx.tcx),
|
||||
captured_place.get_path_span(self.infcx.tcx),
|
||||
|
@ -325,7 +325,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
// Can't have BrEnv in functions, constants or generators.
|
||||
bug!("BrEnv outside of closure.");
|
||||
};
|
||||
let hir::ExprKind::Closure { fn_decl_span, .. }
|
||||
let hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. })
|
||||
= tcx.hir().expect_expr(self.mir_hir_id()).kind
|
||||
else {
|
||||
bug!("Closure is not defined by a closure expr");
|
||||
@ -701,16 +701,16 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
|
||||
let (return_span, mir_description, hir_ty) = match hir.get(mir_hir_id) {
|
||||
hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure { fn_decl, body, fn_decl_span, .. },
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, body, fn_decl_span, .. }),
|
||||
..
|
||||
}) => {
|
||||
let (mut span, mut hir_ty) = match fn_decl.output {
|
||||
hir::FnRetTy::DefaultReturn(_) => {
|
||||
(tcx.sess.source_map().end_point(*fn_decl_span), None)
|
||||
(tcx.sess.source_map().end_point(fn_decl_span), None)
|
||||
}
|
||||
hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)),
|
||||
};
|
||||
let mir_description = match hir.body(*body).generator_kind {
|
||||
let mir_description = match hir.body(body).generator_kind {
|
||||
Some(hir::GeneratorKind::Async(gen)) => match gen {
|
||||
hir::AsyncGeneratorKind::Block => " of async block",
|
||||
hir::AsyncGeneratorKind::Closure => " of async closure",
|
||||
@ -841,9 +841,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
|
||||
let yield_span = match tcx.hir().get(self.mir_hir_id()) {
|
||||
hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure { fn_decl_span, .. },
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
|
||||
..
|
||||
}) => (tcx.sess.source_map().end_point(*fn_decl_span)),
|
||||
}) => (tcx.sess.source_map().end_point(fn_decl_span)),
|
||||
_ => self.body.span,
|
||||
};
|
||||
|
||||
|
@ -294,7 +294,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
||||
| ExprKind::Block(_, _)
|
||||
| ExprKind::Box(_)
|
||||
| ExprKind::Break(_, _)
|
||||
| ExprKind::Closure(_, _, _, _, _, _)
|
||||
| ExprKind::Closure(_, _, _, _, _, _, _)
|
||||
| ExprKind::ConstBlock(_)
|
||||
| ExprKind::Continue(_)
|
||||
| ExprKind::Err
|
||||
|
@ -520,6 +520,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
self.expr(
|
||||
span,
|
||||
ast::ExprKind::Closure(
|
||||
ast::ClosureBinder::NotPresent,
|
||||
ast::CaptureBy::Ref,
|
||||
ast::Async::No,
|
||||
ast::Movability::Movable,
|
||||
|
@ -330,6 +330,8 @@ declare_features! (
|
||||
(active, cfg_target_thread_local, "1.7.0", Some(29594), None),
|
||||
/// Allow conditional compilation depending on rust version
|
||||
(active, cfg_version, "1.45.0", Some(64796), None),
|
||||
/// Allows `for<...>` on closures and generators.
|
||||
(active, closure_lifetime_binder, "1.64.0", Some(97362), None),
|
||||
/// Allows `#[track_caller]` on closures and generators.
|
||||
(active, closure_track_caller, "1.57.0", Some(87417), None),
|
||||
/// Allows to use the `#[cmse_nonsecure_entry]` attribute.
|
||||
|
@ -12,6 +12,7 @@ macro_rules! arena_types {
|
||||
[] asm_operand: (rustc_hir::InlineAsmOperand<'tcx>, rustc_span::Span),
|
||||
[] asm_template: rustc_ast::InlineAsmTemplatePiece,
|
||||
[] attribute: rustc_ast::Attribute,
|
||||
[] closure: rustc_hir::Closure<'tcx>,
|
||||
[] block: rustc_hir::Block<'tcx>,
|
||||
[] bare_fn_ty: rustc_hir::BareFnTy<'tcx>,
|
||||
[] body: rustc_hir::Body<'tcx>,
|
||||
|
@ -922,6 +922,17 @@ pub struct Crate<'hir> {
|
||||
pub hir_hash: Fingerprint,
|
||||
}
|
||||
|
||||
#[derive(Debug, HashStable_Generic)]
|
||||
pub struct Closure<'hir> {
|
||||
pub binder: ClosureBinder,
|
||||
pub capture_clause: CaptureBy,
|
||||
pub bound_generic_params: &'hir [GenericParam<'hir>],
|
||||
pub fn_decl: &'hir FnDecl<'hir>,
|
||||
pub body: BodyId,
|
||||
pub fn_decl_span: Span,
|
||||
pub movability: Option<Movability>,
|
||||
}
|
||||
|
||||
/// A block of statements `{ .. }`, which may have a label (in this case the
|
||||
/// `targeted_by_break` field will be `true`) and may be `unsafe` by means of
|
||||
/// the `rules` being anything but `DefaultBlock`.
|
||||
@ -1915,14 +1926,7 @@ pub enum ExprKind<'hir> {
|
||||
///
|
||||
/// This may also be a generator literal or an `async block` as indicated by the
|
||||
/// `Option<Movability>`.
|
||||
Closure {
|
||||
capture_clause: CaptureBy,
|
||||
bound_generic_params: &'hir [GenericParam<'hir>],
|
||||
fn_decl: &'hir FnDecl<'hir>,
|
||||
body: BodyId,
|
||||
fn_decl_span: Span,
|
||||
movability: Option<Movability>,
|
||||
},
|
||||
Closure(&'hir Closure<'hir>),
|
||||
/// A block (e.g., `'label: { ... }`).
|
||||
Block(&'hir Block<'hir>, Option<Label>),
|
||||
|
||||
@ -2700,6 +2704,17 @@ impl FnRetTy<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents `for<...>` binder before a closure
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic)]
|
||||
pub enum ClosureBinder {
|
||||
/// Binder is not specified.
|
||||
Default,
|
||||
/// Binder is specified.
|
||||
///
|
||||
/// Span points to the whole `for<...>`.
|
||||
For { span: Span },
|
||||
}
|
||||
|
||||
#[derive(Encodable, Debug, HashStable_Generic)]
|
||||
pub struct Mod<'hir> {
|
||||
pub spans: ModSpans,
|
||||
@ -3464,7 +3479,7 @@ impl<'hir> Node<'hir> {
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
mod size_asserts {
|
||||
rustc_data_structures::static_assert_size!(super::Block<'static>, 48);
|
||||
rustc_data_structures::static_assert_size!(super::Expr<'static>, 64);
|
||||
rustc_data_structures::static_assert_size!(super::Expr<'static>, 56);
|
||||
rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
|
||||
rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
|
||||
rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
|
||||
|
@ -928,7 +928,7 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'
|
||||
FnKind::ItemFn(_, generics, ..) => {
|
||||
visitor.visit_generics(generics);
|
||||
}
|
||||
FnKind::Method(..) | FnKind::Closure => {}
|
||||
FnKind::Closure | FnKind::Method(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1147,14 +1147,15 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
||||
visitor.visit_expr(subexpression);
|
||||
walk_list!(visitor, visit_arm, arms);
|
||||
}
|
||||
ExprKind::Closure {
|
||||
ExprKind::Closure(&Closure {
|
||||
binder: _,
|
||||
bound_generic_params,
|
||||
ref fn_decl,
|
||||
fn_decl,
|
||||
body,
|
||||
capture_clause: _,
|
||||
fn_decl_span: _,
|
||||
movability: _,
|
||||
} => {
|
||||
}) => {
|
||||
walk_list!(visitor, visit_generic_param, bound_generic_params);
|
||||
visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
|
||||
use rustc_ast_pretty::pp::{self, Breaks};
|
||||
use rustc_ast_pretty::pprust::{Comments, PrintState};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::LifetimeParamKind;
|
||||
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term};
|
||||
use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
@ -1452,15 +1453,16 @@ impl<'a> State<'a> {
|
||||
}
|
||||
self.bclose(expr.span);
|
||||
}
|
||||
hir::ExprKind::Closure {
|
||||
hir::ExprKind::Closure(&hir::Closure {
|
||||
binder,
|
||||
capture_clause,
|
||||
bound_generic_params,
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: _,
|
||||
movability: _,
|
||||
} => {
|
||||
self.print_formal_generic_params(bound_generic_params);
|
||||
}) => {
|
||||
self.print_closure_binder(binder, bound_generic_params);
|
||||
self.print_capture_clause(capture_clause);
|
||||
|
||||
self.print_closure_params(fn_decl, body);
|
||||
@ -2045,6 +2047,42 @@ impl<'a> State<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_closure_binder(
|
||||
&mut self,
|
||||
binder: hir::ClosureBinder,
|
||||
generic_params: &[GenericParam<'_>],
|
||||
) {
|
||||
let generic_params = generic_params
|
||||
.iter()
|
||||
.filter(|p| {
|
||||
matches!(
|
||||
p,
|
||||
GenericParam {
|
||||
kind: GenericParamKind::Lifetime { kind: LifetimeParamKind::Explicit },
|
||||
..
|
||||
}
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
match binder {
|
||||
hir::ClosureBinder::Default => {}
|
||||
// we need to distinguish `|...| {}` from `for<> |...| {}` as `for<>` adds additional restrictions
|
||||
hir::ClosureBinder::For { .. } if generic_params.is_empty() => self.word("for<>"),
|
||||
hir::ClosureBinder::For { .. } => {
|
||||
self.word("for");
|
||||
self.word("<");
|
||||
|
||||
self.commasep(Inconsistent, &generic_params, |s, param| {
|
||||
s.print_generic_param(param)
|
||||
});
|
||||
|
||||
self.word(">");
|
||||
self.nbsp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_bounds<'b>(
|
||||
&mut self,
|
||||
prefix: &'static str,
|
||||
|
@ -6,7 +6,7 @@ use rustc_hir::def::Res;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Namespace};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
|
||||
use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
||||
@ -1051,7 +1051,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
|
||||
|
||||
if let Some(node_ty) = self.opt_node_type(expr.hir_id) {
|
||||
if let (
|
||||
&ExprKind::Closure { fn_decl, body, fn_decl_span, .. },
|
||||
&ExprKind::Closure(&Closure { fn_decl, body, fn_decl_span, .. }),
|
||||
ty::Closure(_, substs),
|
||||
) = (&expr.kind, node_ty.kind())
|
||||
{
|
||||
|
@ -154,6 +154,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
||||
self.check_id(closure_id);
|
||||
}
|
||||
}
|
||||
|
||||
run_early_pass!(self, check_fn_post, fk, span, id);
|
||||
}
|
||||
|
||||
@ -218,7 +219,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
||||
// Explicitly check for lints associated with 'closure_id', since
|
||||
// it does not have a corresponding AST node
|
||||
match e.kind {
|
||||
ast::ExprKind::Closure(_, ast::Async::Yes { closure_id, .. }, ..)
|
||||
ast::ExprKind::Closure(_, _, ast::Async::Yes { closure_id, .. }, ..)
|
||||
| ast::ExprKind::Async(_, closure_id, ..) => self.check_id(closure_id),
|
||||
_ => {}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> {
|
||||
Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
|
||||
| Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. })
|
||||
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(&sig.decl),
|
||||
Node::Expr(Expr { kind: ExprKind::Closure { fn_decl, .. }, .. })
|
||||
Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. })
|
||||
| Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, ..), .. }) => {
|
||||
Some(fn_decl)
|
||||
}
|
||||
@ -54,7 +54,7 @@ pub fn associated_body<'hir>(node: Node<'hir>) -> Option<BodyId> {
|
||||
kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body),
|
||||
..
|
||||
})
|
||||
| Node::Expr(Expr { kind: ExprKind::Closure { body, .. }, .. }) => Some(*body),
|
||||
| Node::Expr(Expr { kind: ExprKind::Closure(Closure { body, .. }), .. }) => Some(*body),
|
||||
|
||||
Node::AnonConst(constant) => Some(constant.body),
|
||||
|
||||
@ -279,8 +279,8 @@ impl<'hir> Map<'hir> {
|
||||
}
|
||||
Node::Field(_) => DefKind::Field,
|
||||
Node::Expr(expr) => match expr.kind {
|
||||
ExprKind::Closure { movability: None, .. } => DefKind::Closure,
|
||||
ExprKind::Closure { movability: Some(_), .. } => DefKind::Generator,
|
||||
ExprKind::Closure(Closure { movability: None, .. }) => DefKind::Closure,
|
||||
ExprKind::Closure(Closure { movability: Some(_), .. }) => DefKind::Generator,
|
||||
_ => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)),
|
||||
},
|
||||
Node::GenericParam(param) => match param.kind {
|
||||
@ -1021,7 +1021,9 @@ impl<'hir> Map<'hir> {
|
||||
_ => named_span(item.span, item.ident, None),
|
||||
},
|
||||
Node::Ctor(_) => return self.opt_span(self.get_parent_node(hir_id)),
|
||||
Node::Expr(Expr { kind: ExprKind::Closure { fn_decl_span, .. }, .. }) => *fn_decl_span,
|
||||
Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl_span, .. }), .. }) => {
|
||||
*fn_decl_span
|
||||
}
|
||||
_ => self.span_with_body(hir_id),
|
||||
};
|
||||
Some(span)
|
||||
|
@ -68,9 +68,10 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
|
||||
|
||||
// Figure out what primary body this item has.
|
||||
let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) {
|
||||
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { fn_decl, body, .. }, .. }) => {
|
||||
(*body, fn_decl.output.span(), None)
|
||||
}
|
||||
Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure(hir::Closure { fn_decl, body, .. }),
|
||||
..
|
||||
}) => (*body, fn_decl.output.span(), None),
|
||||
Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Fn(hir::FnSig { decl, .. }, _, body_id),
|
||||
span,
|
||||
|
@ -15,10 +15,10 @@ use rustc_ast::util::classify;
|
||||
use rustc_ast::util::literal::LitError;
|
||||
use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_ast::StmtKind;
|
||||
use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, Lit, UnOp, DUMMY_NODE_ID};
|
||||
use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind};
|
||||
use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
|
||||
use rustc_ast::{ClosureBinder, StmtKind};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult};
|
||||
@ -1343,11 +1343,7 @@ impl<'a> Parser<'a> {
|
||||
self.parse_if_expr(attrs)
|
||||
} else if self.check_keyword(kw::For) {
|
||||
if self.choose_generics_over_qpath(1) {
|
||||
// NOTE(Centril, eddyb): DO NOT REMOVE! Beyond providing parser recovery,
|
||||
// this is an insurance policy in case we allow qpaths in (tuple-)struct patterns.
|
||||
// When `for <Foo as Bar>::Proj in $expr $block` is wanted,
|
||||
// you can disambiguate in favor of a pattern with `(...)`.
|
||||
self.recover_quantified_closure_expr(attrs)
|
||||
self.parse_closure_expr(attrs)
|
||||
} else {
|
||||
assert!(self.eat_keyword(kw::For));
|
||||
self.parse_for_expr(None, self.prev_token.span, attrs)
|
||||
@ -2096,30 +2092,22 @@ impl<'a> Parser<'a> {
|
||||
Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()))
|
||||
}
|
||||
|
||||
/// Recover on an explicitly quantified closure expression, e.g., `for<'a> |x: &'a u8| *x + 1`.
|
||||
fn recover_quantified_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
let lo = self.token.span;
|
||||
let _ = self.parse_late_bound_lifetime_defs()?;
|
||||
let span_for = lo.to(self.prev_token.span);
|
||||
let closure = self.parse_closure_expr(attrs)?;
|
||||
|
||||
self.struct_span_err(span_for, "cannot introduce explicit parameters for a closure")
|
||||
.span_label(closure.span, "the parameters are attached to this closure")
|
||||
.span_suggestion(
|
||||
span_for,
|
||||
"remove the parameters",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
||||
Ok(self.mk_expr_err(lo.to(closure.span)))
|
||||
}
|
||||
|
||||
/// Parses a closure expression (e.g., `move |args| expr`).
|
||||
fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
let lo = self.token.span;
|
||||
|
||||
let binder = if self.check_keyword(kw::For) {
|
||||
let lo = self.token.span;
|
||||
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
|
||||
let span = lo.to(self.prev_token.span);
|
||||
|
||||
self.sess.gated_spans.gate(sym::closure_lifetime_binder, span);
|
||||
|
||||
ClosureBinder::For { span, generic_params: P::from_vec(lifetime_defs) }
|
||||
} else {
|
||||
ClosureBinder::NotPresent
|
||||
};
|
||||
|
||||
let movability =
|
||||
if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
|
||||
|
||||
@ -2162,7 +2150,15 @@ impl<'a> Parser<'a> {
|
||||
|
||||
let closure = self.mk_expr(
|
||||
lo.to(body.span),
|
||||
ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)),
|
||||
ExprKind::Closure(
|
||||
binder,
|
||||
capture_clause,
|
||||
asyncness,
|
||||
movability,
|
||||
decl,
|
||||
body,
|
||||
lo.to(decl_hi),
|
||||
),
|
||||
attrs,
|
||||
);
|
||||
|
||||
|
@ -57,7 +57,13 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||
hir::ExprKind::Loop(ref b, _, source, _) => {
|
||||
self.with_context(Loop(source), |v| v.visit_block(&b));
|
||||
}
|
||||
hir::ExprKind::Closure { ref fn_decl, body, fn_decl_span, movability, .. } => {
|
||||
hir::ExprKind::Closure(&hir::Closure {
|
||||
ref fn_decl,
|
||||
body,
|
||||
fn_decl_span,
|
||||
movability,
|
||||
..
|
||||
}) => {
|
||||
let cx = if let Some(Movability::Static) = movability {
|
||||
AsyncClosure(fn_decl_span)
|
||||
} else {
|
||||
|
@ -273,7 +273,10 @@ impl<'tcx> ReachableContext<'tcx> {
|
||||
}
|
||||
hir::ImplItemKind::TyAlias(_) => {}
|
||||
},
|
||||
Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { body, .. }, .. }) => {
|
||||
Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { body, .. }),
|
||||
..
|
||||
}) => {
|
||||
self.visit_nested_body(body);
|
||||
}
|
||||
// Nothing to recurse on for these
|
||||
|
@ -259,7 +259,7 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
|
||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
let parent_def = match expr.kind {
|
||||
ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id),
|
||||
ExprKind::Closure(_, asyncness, ..) => {
|
||||
ExprKind::Closure(_, _, asyncness, ..) => {
|
||||
// Async closures desugar to closures inside of closures, so
|
||||
// we must create two defs.
|
||||
let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span);
|
||||
|
@ -268,6 +268,7 @@ enum LifetimeBinderKind {
|
||||
WhereBound,
|
||||
Item,
|
||||
Function,
|
||||
Closure,
|
||||
ImplBlock,
|
||||
}
|
||||
|
||||
@ -281,6 +282,7 @@ impl LifetimeBinderKind {
|
||||
Item => "item",
|
||||
ImplBlock => "impl block",
|
||||
Function => "function",
|
||||
Closure => "closure",
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -866,19 +868,30 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
this.in_func_body = previous_state;
|
||||
}
|
||||
}
|
||||
FnKind::Closure(declaration, body) => {
|
||||
// We do not have any explicit generic lifetime parameter.
|
||||
// FIXME(rfc3216): Change when implementing `for<>` bounds on closures.
|
||||
FnKind::Closure(binder, declaration, body) => {
|
||||
this.visit_closure_binder(binder);
|
||||
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousCreateParameter {
|
||||
binder: fn_id,
|
||||
report_in_path: false,
|
||||
match binder {
|
||||
// We do not have any explicit generic lifetime parameter.
|
||||
ClosureBinder::NotPresent => {
|
||||
LifetimeRibKind::AnonymousCreateParameter {
|
||||
binder: fn_id,
|
||||
report_in_path: false,
|
||||
}
|
||||
}
|
||||
ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError,
|
||||
},
|
||||
// Add each argument to the rib.
|
||||
|this| this.resolve_params(&declaration.inputs),
|
||||
);
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousPassThrough(fn_id, true),
|
||||
match binder {
|
||||
ClosureBinder::NotPresent => {
|
||||
LifetimeRibKind::AnonymousPassThrough(fn_id, true)
|
||||
}
|
||||
ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError,
|
||||
},
|
||||
|this| visit::walk_fn_ret_ty(this, &declaration.output),
|
||||
);
|
||||
|
||||
@ -913,6 +926,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) {
|
||||
match b {
|
||||
ClosureBinder::NotPresent => {}
|
||||
ClosureBinder::For { generic_params, .. } => {
|
||||
self.visit_generic_params(
|
||||
&generic_params,
|
||||
self.diagnostic_metadata.current_self_item.is_some(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
|
||||
debug!("visit_generic_arg({:?})", arg);
|
||||
let prev = replace(&mut self.diagnostic_metadata.currently_processing_generics, true);
|
||||
@ -3517,7 +3542,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
// `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
|
||||
// resolve the arguments within the proper scopes so that usages of them inside the
|
||||
// closure are detected as upvars rather than normal closure arg usages.
|
||||
ExprKind::Closure(_, Async::Yes { .. }, _, ref fn_decl, ref body, _span) => {
|
||||
ExprKind::Closure(_, _, Async::Yes { .. }, _, ref fn_decl, ref body, _span) => {
|
||||
self.with_rib(ValueNS, NormalRibKind, |this| {
|
||||
this.with_label_rib(ClosureOrAsyncRibKind, |this| {
|
||||
// Resolve arguments:
|
||||
@ -3537,6 +3562,18 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
});
|
||||
}
|
||||
// For closures, ClosureOrAsyncRibKind is added in visit_fn
|
||||
ExprKind::Closure(ClosureBinder::For { ref generic_params, span }, ..) => {
|
||||
self.with_generic_param_rib(
|
||||
&generic_params,
|
||||
NormalRibKind,
|
||||
LifetimeRibKind::Generics {
|
||||
binder: expr.id,
|
||||
kind: LifetimeBinderKind::Closure,
|
||||
span,
|
||||
},
|
||||
|this| visit::walk_expr(this, expr),
|
||||
);
|
||||
}
|
||||
ExprKind::Closure(..) => visit::walk_expr(self, expr),
|
||||
ExprKind::Async(..) => {
|
||||
self.with_label_rib(ClosureOrAsyncRibKind, |this| visit::walk_expr(this, expr));
|
||||
|
@ -70,6 +70,8 @@ pub(crate) enum ForLifetimeSpanType {
|
||||
BoundTail,
|
||||
TypeEmpty,
|
||||
TypeTail,
|
||||
ClosureEmpty,
|
||||
ClosureTail,
|
||||
}
|
||||
|
||||
impl ForLifetimeSpanType {
|
||||
@ -77,13 +79,15 @@ impl ForLifetimeSpanType {
|
||||
match self {
|
||||
Self::BoundEmpty | Self::BoundTail => "bound",
|
||||
Self::TypeEmpty | Self::TypeTail => "type",
|
||||
Self::ClosureEmpty | Self::ClosureTail => "closure",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn suggestion(&self, sugg: &str) -> String {
|
||||
match self {
|
||||
Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg),
|
||||
Self::BoundTail | Self::TypeTail => format!(", {}", sugg),
|
||||
Self::ClosureEmpty => format!("for<{}>", sugg),
|
||||
Self::BoundTail | Self::TypeTail | Self::ClosureTail => format!(", {}", sugg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefIdMap, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
|
||||
use rustc_hir::{GenericParamKind, HirIdMap};
|
||||
use rustc_hir::{GenericParamKind, HirIdMap, LifetimeParamKind};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::middle::resolve_lifetime::*;
|
||||
@ -571,7 +571,54 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
|
||||
if let hir::ExprKind::Closure { bound_generic_params, .. } = e.kind {
|
||||
if let hir::ExprKind::Closure(hir::Closure {
|
||||
binder, bound_generic_params, fn_decl, ..
|
||||
}) = e.kind
|
||||
{
|
||||
if let &hir::ClosureBinder::For { span: for_sp, .. } = binder {
|
||||
fn span_of_infer(ty: &hir::Ty<'_>) -> Option<Span> {
|
||||
struct V(Option<Span>);
|
||||
|
||||
impl<'v> Visitor<'v> for V {
|
||||
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
|
||||
match t.kind {
|
||||
_ if self.0.is_some() => (),
|
||||
hir::TyKind::Infer => {
|
||||
self.0 = Some(t.span);
|
||||
}
|
||||
_ => intravisit::walk_ty(self, t),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut v = V(None);
|
||||
v.visit_ty(ty);
|
||||
v.0
|
||||
}
|
||||
|
||||
let infer_in_rt_sp = match fn_decl.output {
|
||||
hir::FnRetTy::DefaultReturn(sp) => Some(sp),
|
||||
hir::FnRetTy::Return(ty) => span_of_infer(ty),
|
||||
};
|
||||
|
||||
let infer_spans = fn_decl
|
||||
.inputs
|
||||
.into_iter()
|
||||
.filter_map(span_of_infer)
|
||||
.chain(infer_in_rt_sp)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !infer_spans.is_empty() {
|
||||
self.tcx.sess
|
||||
.struct_span_err(
|
||||
infer_spans,
|
||||
"implicit types in closure signatures are forbidden when `for<...>` is present",
|
||||
)
|
||||
.span_label(for_sp, "`for<...>` is here")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
let next_early_index = self.next_early_index();
|
||||
let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
|
||||
bound_generic_params
|
||||
@ -584,6 +631,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
(pair, r)
|
||||
})
|
||||
.unzip();
|
||||
|
||||
self.map.late_bound_vars.insert(e.hir_id, binders);
|
||||
let scope = Scope::Binder {
|
||||
hir_id: e.hir_id,
|
||||
@ -595,11 +643,41 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
allow_late_bound: true,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
|
||||
if let &hir::ClosureBinder::For { span, .. } = binder {
|
||||
let last_lt = bound_generic_params
|
||||
.iter()
|
||||
.filter(|p| {
|
||||
matches!(
|
||||
p,
|
||||
GenericParam {
|
||||
kind: GenericParamKind::Lifetime {
|
||||
kind: LifetimeParamKind::Explicit
|
||||
},
|
||||
..
|
||||
}
|
||||
)
|
||||
})
|
||||
.last();
|
||||
let (span, span_type) = match last_lt {
|
||||
Some(GenericParam { span: last_sp, .. }) => {
|
||||
(last_sp.shrink_to_hi(), ForLifetimeSpanType::ClosureTail)
|
||||
}
|
||||
None => (span, ForLifetimeSpanType::ClosureEmpty),
|
||||
};
|
||||
self.missing_named_lifetime_spots
|
||||
.push(MissingLifetimeSpot::HigherRanked { span, span_type });
|
||||
}
|
||||
|
||||
self.with(scope, |this| {
|
||||
// a closure has no bounds, so everything
|
||||
// contained within is scoped within its binder.
|
||||
intravisit::walk_expr(this, e)
|
||||
});
|
||||
|
||||
if let hir::ClosureBinder::For { .. } = binder {
|
||||
self.missing_named_lifetime_spots.pop();
|
||||
}
|
||||
} else {
|
||||
intravisit::walk_expr(self, e)
|
||||
}
|
||||
|
@ -1353,7 +1353,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Closure { ref fn_decl, body, .. } => {
|
||||
hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, .. }) => {
|
||||
let id = format!("${}", ex.hir_id);
|
||||
|
||||
// walk arg and return types
|
||||
|
@ -460,6 +460,7 @@ symbols! {
|
||||
clone_closures,
|
||||
clone_from,
|
||||
closure,
|
||||
closure_lifetime_binder,
|
||||
closure_to_fn_coercion,
|
||||
closure_track_caller,
|
||||
cmp,
|
||||
|
@ -1086,7 +1086,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
let hir = self.tcx.hir();
|
||||
Some(match node {
|
||||
Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Closure { body, fn_decl_span, .. },
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }),
|
||||
..
|
||||
}) => (
|
||||
sm.guess_head_span(fn_decl_span),
|
||||
|
@ -103,7 +103,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
})
|
||||
}),
|
||||
hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure { body, movability, .. },
|
||||
kind: hir::ExprKind::Closure(hir::Closure { body, movability, .. }),
|
||||
..
|
||||
}) => self.describe_generator(*body).or_else(|| {
|
||||
Some(if movability.is_some() { "an async closure" } else { "a closure" })
|
||||
|
@ -786,7 +786,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
// Get the name of the callable and the arguments to be used in the suggestion.
|
||||
let (snippet, sugg) = match hir.get_if_local(def_id) {
|
||||
Some(hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure { fn_decl, fn_decl_span, .. },
|
||||
kind: hir::ExprKind::Closure(hir::Closure { fn_decl, fn_decl_span, .. }),
|
||||
..
|
||||
})) => {
|
||||
err.span_label(*fn_decl_span, "consider calling this closure");
|
||||
|
@ -285,29 +285,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let parent_node = hir.get(parent_hir_id);
|
||||
if let (
|
||||
hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure { fn_decl_span, body, .. },
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, body, .. }),
|
||||
..
|
||||
}),
|
||||
hir::ExprKind::Block(..),
|
||||
) = (parent_node, callee_node)
|
||||
{
|
||||
let fn_decl_span = if hir.body(*body).generator_kind
|
||||
let fn_decl_span = if hir.body(body).generator_kind
|
||||
== Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure))
|
||||
{
|
||||
// Actually need to unwrap a few more layers of HIR to get to
|
||||
// the _real_ closure...
|
||||
let async_closure = hir.get_parent_node(hir.get_parent_node(parent_hir_id));
|
||||
if let hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure { fn_decl_span, .. },
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
|
||||
..
|
||||
}) = hir.get(async_closure)
|
||||
{
|
||||
*fn_decl_span
|
||||
fn_decl_span
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
*fn_decl_span
|
||||
fn_decl_span
|
||||
};
|
||||
|
||||
let start = fn_decl_span.shrink_to_lo();
|
||||
|
@ -1577,8 +1577,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||
let parent_id = fcx.tcx.hir().get_parent_node(id);
|
||||
let parent = fcx.tcx.hir().get(parent_id);
|
||||
if let Some(expr) = expression
|
||||
&& let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { body, .. }, .. }) = parent
|
||||
&& !matches!(fcx.tcx.hir().body(*body).value.kind, hir::ExprKind::Block(..))
|
||||
&& let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), .. }) = parent
|
||||
&& !matches!(fcx.tcx.hir().body(body).value.kind, hir::ExprKind::Block(..))
|
||||
{
|
||||
fcx.suggest_missing_semicolon(&mut err, expr, expected, true);
|
||||
}
|
||||
|
@ -483,7 +483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let param_parent = self.tcx.hir().get_parent_node(*param_hir_id);
|
||||
let Some(Node::Expr(hir::Expr {
|
||||
hir_id: expr_hir_id,
|
||||
kind: hir::ExprKind::Closure { fn_decl: closure_fn_decl, .. },
|
||||
kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }),
|
||||
..
|
||||
})) = self.tcx.hir().find(param_parent) else {
|
||||
return None;
|
||||
|
@ -35,7 +35,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ExprKind, HirId, QPath};
|
||||
use rustc_hir::{Closure, ExprKind, HirId, QPath};
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::InferOk;
|
||||
@ -319,7 +319,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ExprKind::Match(discrim, arms, match_src) => {
|
||||
self.check_match(expr, &discrim, arms, expected, match_src)
|
||||
}
|
||||
ExprKind::Closure { capture_clause, fn_decl, body, movability, .. } => {
|
||||
ExprKind::Closure(&Closure { capture_clause, fn_decl, body, movability, .. }) => {
|
||||
self.check_expr_closure(expr, capture_clause, &fn_decl, body, movability, expected)
|
||||
}
|
||||
ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected),
|
||||
|
@ -1825,7 +1825,7 @@ fn label_fn_like<'tcx>(
|
||||
} else {
|
||||
match tcx.hir().get_if_local(def_id) {
|
||||
Some(hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure { fn_decl_span, .. },
|
||||
kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }),
|
||||
..
|
||||
})) => {
|
||||
let spans: MultiSpan = (*fn_decl_span).into();
|
||||
|
@ -335,7 +335,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
|
||||
match expr.kind {
|
||||
// Manually recurse over closures and inline consts, because they are the only
|
||||
// case of nested bodies that share the parent environment.
|
||||
hir::ExprKind::Closure { body, .. }
|
||||
hir::ExprKind::Closure(&hir::Closure { body, .. })
|
||||
| hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => {
|
||||
let body = visitor.tcx.hir().body(body);
|
||||
visitor.visit_body(body);
|
||||
|
@ -142,7 +142,7 @@ struct InferBorrowKindVisitor<'a, 'tcx> {
|
||||
impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
match expr.kind {
|
||||
hir::ExprKind::Closure { capture_clause, body: body_id, .. } => {
|
||||
hir::ExprKind::Closure(&hir::Closure { capture_clause, body: body_id, .. }) => {
|
||||
let body = self.fcx.tcx.hir().body(body_id);
|
||||
self.visit_body(body);
|
||||
self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause);
|
||||
|
@ -263,7 +263,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
||||
self.fix_index_builtin_expr(e);
|
||||
|
||||
match e.kind {
|
||||
hir::ExprKind::Closure { body, .. } => {
|
||||
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
|
||||
let body = self.fcx.tcx.hir().body(body);
|
||||
for param in body.params {
|
||||
self.visit_node_id(e.span, param.hir_id);
|
||||
|
@ -1717,8 +1717,10 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
// provide junk type parameter defs - the only place that
|
||||
// cares about anything but the length is instantiation,
|
||||
// and we don't do that for closures.
|
||||
if let Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { movability: gen, .. }, .. }) =
|
||||
node
|
||||
if let Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }),
|
||||
..
|
||||
}) = node
|
||||
{
|
||||
let dummy_args = if gen.is_some() {
|
||||
&["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
|
||||
@ -2564,7 +2566,7 @@ fn is_foreign_item(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind> {
|
||||
match tcx.hir().get_if_local(def_id) {
|
||||
Some(Node::Expr(&rustc_hir::Expr {
|
||||
kind: rustc_hir::ExprKind::Closure { body, .. },
|
||||
kind: rustc_hir::ExprKind::Closure(&rustc_hir::Closure { body, .. }),
|
||||
..
|
||||
})) => tcx.hir().body(body).generator_kind(),
|
||||
Some(_) => None,
|
||||
|
@ -114,6 +114,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
|
||||
let decl = P(FnDecl { inputs: vec![], output: FnRetTy::Default(DUMMY_SP) });
|
||||
iter_exprs(depth - 1, &mut |e| {
|
||||
g(ExprKind::Closure(
|
||||
ClosureBinder::NotPresent,
|
||||
CaptureBy::Value,
|
||||
Async::No,
|
||||
Movability::Movable,
|
||||
|
8
src/test/ui/closures/binder/async-closure-with-binder.rs
Normal file
8
src/test/ui/closures/binder/async-closure-with-binder.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// edition:2021
|
||||
#![feature(closure_lifetime_binder)]
|
||||
#![feature(async_closure)]
|
||||
fn main() {
|
||||
for<'a> async || ();
|
||||
//~^ ERROR `for<...>` binders on `async` closures are not currently supported
|
||||
//~^^ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
}
|
16
src/test/ui/closures/binder/async-closure-with-binder.stderr
Normal file
16
src/test/ui/closures/binder/async-closure-with-binder.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error: `for<...>` binders on `async` closures are not currently supported
|
||||
--> $DIR/async-closure-with-binder.rs:5:5
|
||||
|
|
||||
LL | for<'a> async || ();
|
||||
| ^^^^^^^
|
||||
|
||||
error: implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
--> $DIR/async-closure-with-binder.rs:5:5
|
||||
|
|
||||
LL | for<'a> async || ();
|
||||
| -------^^^^^^^^^
|
||||
| |
|
||||
| `for<...>` is here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
6
src/test/ui/closures/binder/implicit-return.rs
Normal file
6
src/test/ui/closures/binder/implicit-return.rs
Normal file
@ -0,0 +1,6 @@
|
||||
#![feature(closure_lifetime_binder)]
|
||||
|
||||
fn main() {
|
||||
let _f = for<'a> |_: &'a ()| {};
|
||||
//~^ implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
}
|
10
src/test/ui/closures/binder/implicit-return.stderr
Normal file
10
src/test/ui/closures/binder/implicit-return.stderr
Normal file
@ -0,0 +1,10 @@
|
||||
error: implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
--> $DIR/implicit-return.rs:4:34
|
||||
|
|
||||
LL | let _f = for<'a> |_: &'a ()| {};
|
||||
| ------- ^
|
||||
| |
|
||||
| `for<...>` is here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
27
src/test/ui/closures/binder/implicit-stuff.rs
Normal file
27
src/test/ui/closures/binder/implicit-stuff.rs
Normal file
@ -0,0 +1,27 @@
|
||||
#![feature(closure_lifetime_binder)]
|
||||
|
||||
fn main() {
|
||||
// Implicit types
|
||||
let _ = for<> || {}; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
let _ = for<'a> || -> &'a _ { &() }; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
let _ = for<'a> |x| -> &'a () { x }; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
let _ = for<'a> |x: &'a _| -> &'a () { x }; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
let _ = for<'a> |x: &'a Vec::<_>| -> &'a Vec::<()> { x }; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
let _ = for<'a> |x: &'a Vec<()>| -> &'a Vec<_> { x }; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
let _ = for<'a> |x: &'a _| -> &'a &'a () { x }; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
let _ = for<'a> |x: &'a _, y, z: _| -> &'a _ { //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
let _: &u8 = x;
|
||||
let _: u32 = y;
|
||||
let _: i32 = z;
|
||||
x
|
||||
};
|
||||
|
||||
// Lifetime elision
|
||||
let _ = for<> |_: &()| -> () {}; //~ ERROR `&` without an explicit lifetime name cannot be used here
|
||||
let _ = for<> |x: &()| -> &() { x }; //~ ERROR `&` without an explicit lifetime name cannot be used here
|
||||
//~| ERROR `&` without an explicit lifetime name cannot be used here
|
||||
let _ = for<> |x: &'_ ()| -> &'_ () { x }; //~ ERROR `'_` cannot be used here
|
||||
//~| ERROR `'_` cannot be used here
|
||||
let _ = for<'a> |x: &()| -> &'a () { x }; //~ ERROR `&` without an explicit lifetime name cannot be used here
|
||||
let _ = for<'a> |x: &'a ()| -> &() { x }; //~ ERROR `&` without an explicit lifetime name cannot be used here
|
||||
}
|
107
src/test/ui/closures/binder/implicit-stuff.stderr
Normal file
107
src/test/ui/closures/binder/implicit-stuff.stderr
Normal file
@ -0,0 +1,107 @@
|
||||
error[E0637]: `&` without an explicit lifetime name cannot be used here
|
||||
--> $DIR/implicit-stuff.rs:20:23
|
||||
|
|
||||
LL | let _ = for<> |_: &()| -> () {};
|
||||
| ^ explicit lifetime name needed here
|
||||
|
||||
error[E0637]: `&` without an explicit lifetime name cannot be used here
|
||||
--> $DIR/implicit-stuff.rs:21:23
|
||||
|
|
||||
LL | let _ = for<> |x: &()| -> &() { x };
|
||||
| ^ explicit lifetime name needed here
|
||||
|
||||
error[E0637]: `&` without an explicit lifetime name cannot be used here
|
||||
--> $DIR/implicit-stuff.rs:21:31
|
||||
|
|
||||
LL | let _ = for<> |x: &()| -> &() { x };
|
||||
| ^ explicit lifetime name needed here
|
||||
|
||||
error[E0637]: `'_` cannot be used here
|
||||
--> $DIR/implicit-stuff.rs:23:24
|
||||
|
|
||||
LL | let _ = for<> |x: &'_ ()| -> &'_ () { x };
|
||||
| ^^ `'_` is a reserved lifetime name
|
||||
|
||||
error[E0637]: `'_` cannot be used here
|
||||
--> $DIR/implicit-stuff.rs:23:35
|
||||
|
|
||||
LL | let _ = for<> |x: &'_ ()| -> &'_ () { x };
|
||||
| ^^ `'_` is a reserved lifetime name
|
||||
|
||||
error[E0637]: `&` without an explicit lifetime name cannot be used here
|
||||
--> $DIR/implicit-stuff.rs:25:25
|
||||
|
|
||||
LL | let _ = for<'a> |x: &()| -> &'a () { x };
|
||||
| ^ explicit lifetime name needed here
|
||||
|
||||
error[E0637]: `&` without an explicit lifetime name cannot be used here
|
||||
--> $DIR/implicit-stuff.rs:26:36
|
||||
|
|
||||
LL | let _ = for<'a> |x: &'a ()| -> &() { x };
|
||||
| ^ explicit lifetime name needed here
|
||||
|
||||
error: implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
--> $DIR/implicit-stuff.rs:5:22
|
||||
|
|
||||
LL | let _ = for<> || {};
|
||||
| ----- ^
|
||||
| |
|
||||
| `for<...>` is here
|
||||
|
||||
error: implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
--> $DIR/implicit-stuff.rs:6:31
|
||||
|
|
||||
LL | let _ = for<'a> || -> &'a _ { &() };
|
||||
| ------- ^
|
||||
| |
|
||||
| `for<...>` is here
|
||||
|
||||
error: implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
--> $DIR/implicit-stuff.rs:7:22
|
||||
|
|
||||
LL | let _ = for<'a> |x| -> &'a () { x };
|
||||
| ------- ^
|
||||
| |
|
||||
| `for<...>` is here
|
||||
|
||||
error: implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
--> $DIR/implicit-stuff.rs:8:29
|
||||
|
|
||||
LL | let _ = for<'a> |x: &'a _| -> &'a () { x };
|
||||
| ------- ^
|
||||
| |
|
||||
| `for<...>` is here
|
||||
|
||||
error: implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
--> $DIR/implicit-stuff.rs:9:35
|
||||
|
|
||||
LL | let _ = for<'a> |x: &'a Vec::<_>| -> &'a Vec::<()> { x };
|
||||
| ------- ^
|
||||
| |
|
||||
| `for<...>` is here
|
||||
|
||||
error: implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
--> $DIR/implicit-stuff.rs:10:49
|
||||
|
|
||||
LL | let _ = for<'a> |x: &'a Vec<()>| -> &'a Vec<_> { x };
|
||||
| ------- `for<...>` is here ^
|
||||
|
||||
error: implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
--> $DIR/implicit-stuff.rs:11:29
|
||||
|
|
||||
LL | let _ = for<'a> |x: &'a _| -> &'a &'a () { x };
|
||||
| ------- ^
|
||||
| |
|
||||
| `for<...>` is here
|
||||
|
||||
error: implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
--> $DIR/implicit-stuff.rs:12:29
|
||||
|
|
||||
LL | let _ = for<'a> |x: &'a _, y, z: _| -> &'a _ {
|
||||
| ------- ^ ^ ^ ^
|
||||
| |
|
||||
| `for<...>` is here
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0637`.
|
@ -0,0 +1,7 @@
|
||||
#![feature(closure_lifetime_binder)]
|
||||
fn main() {
|
||||
for<> |_: &'a ()| -> () {};
|
||||
//~^ ERROR use of undeclared lifetime name `'a`
|
||||
for<'a> |_: &'b ()| -> () {};
|
||||
//~^ ERROR use of undeclared lifetime name `'b`
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
error[E0261]: use of undeclared lifetime name `'a`
|
||||
--> $DIR/suggestion-for-introducing-lifetime-into-binder.rs:3:16
|
||||
|
|
||||
LL | for<> |_: &'a ()| -> () {};
|
||||
| ^^ undeclared lifetime
|
||||
|
|
||||
help: consider introducing lifetime `'a` here
|
||||
|
|
||||
LL | for<'a, > |_: &'a ()| -> () {};
|
||||
| +++
|
||||
help: consider introducing lifetime `'a` here
|
||||
|
|
||||
LL | fn main<'a>() {
|
||||
| ++++
|
||||
|
||||
error[E0261]: use of undeclared lifetime name `'b`
|
||||
--> $DIR/suggestion-for-introducing-lifetime-into-binder.rs:5:18
|
||||
|
|
||||
LL | for<'a> |_: &'b ()| -> () {};
|
||||
| ^^ undeclared lifetime
|
||||
|
|
||||
help: consider introducing lifetime `'b` here
|
||||
|
|
||||
LL | for<'b, 'a> |_: &'b ()| -> () {};
|
||||
| +++
|
||||
help: consider introducing lifetime `'b` here
|
||||
|
|
||||
LL | fn main<'b>() {
|
||||
| ++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0261`.
|
@ -0,0 +1,8 @@
|
||||
fn main() {
|
||||
for<> || -> () {};
|
||||
//~^ ERROR `for<...>` binders for closures are experimental
|
||||
for<'a> || -> () {};
|
||||
//~^ ERROR `for<...>` binders for closures are experimental
|
||||
for<'a, 'b> |_: &'a ()| -> () {};
|
||||
//~^ ERROR `for<...>` binders for closures are experimental
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
error[E0658]: `for<...>` binders for closures are experimental
|
||||
--> $DIR/feature-gate-closure_lifetime_binder.rs:2:5
|
||||
|
|
||||
LL | for<> || -> () {};
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
|
||||
= help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
|
||||
= help: consider removing `for<...>`
|
||||
|
||||
error[E0658]: `for<...>` binders for closures are experimental
|
||||
--> $DIR/feature-gate-closure_lifetime_binder.rs:4:5
|
||||
|
|
||||
LL | for<'a> || -> () {};
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
|
||||
= help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
|
||||
= help: consider removing `for<...>`
|
||||
|
||||
error[E0658]: `for<...>` binders for closures are experimental
|
||||
--> $DIR/feature-gate-closure_lifetime_binder.rs:6:5
|
||||
|
|
||||
LL | for<'a, 'b> |_: &'a ()| -> () {};
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
|
||||
= help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
|
||||
= help: consider removing `for<...>`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -1,10 +1,12 @@
|
||||
fn main() {
|
||||
for<'a> |x: &'a u8| *x + 1;
|
||||
//~^ ERROR cannot introduce explicit parameters for a closure
|
||||
//~^ ERROR `for<...>` binders for closures are experimental
|
||||
//~^^ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
}
|
||||
|
||||
enum Foo { Bar }
|
||||
fn foo(x: impl Iterator<Item = Foo>) {
|
||||
for <Foo>::Bar in x {}
|
||||
//~^ ERROR expected one of `move`, `static`, `|`
|
||||
//~^^ ERROR `for<...>` binders for closures are experimental
|
||||
}
|
||||
|
@ -1,16 +1,37 @@
|
||||
error: cannot introduce explicit parameters for a closure
|
||||
--> $DIR/recover-quantified-closure.rs:2:5
|
||||
|
|
||||
LL | for<'a> |x: &'a u8| *x + 1;
|
||||
| ^^^^^^^ ------------------ the parameters are attached to this closure
|
||||
| |
|
||||
| help: remove the parameters
|
||||
|
||||
error: expected one of `move`, `static`, `|`, or `||`, found `::`
|
||||
--> $DIR/recover-quantified-closure.rs:8:14
|
||||
--> $DIR/recover-quantified-closure.rs:9:14
|
||||
|
|
||||
LL | for <Foo>::Bar in x {}
|
||||
| ^^ expected one of `move`, `static`, `|`, or `||`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0658]: `for<...>` binders for closures are experimental
|
||||
--> $DIR/recover-quantified-closure.rs:2:5
|
||||
|
|
||||
LL | for<'a> |x: &'a u8| *x + 1;
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
|
||||
= help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
|
||||
= help: consider removing `for<...>`
|
||||
|
||||
error[E0658]: `for<...>` binders for closures are experimental
|
||||
--> $DIR/recover-quantified-closure.rs:9:5
|
||||
|
|
||||
LL | for <Foo>::Bar in x {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
|
||||
= help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
|
||||
= help: consider removing `for<...>`
|
||||
|
||||
error: implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
--> $DIR/recover-quantified-closure.rs:2:25
|
||||
|
|
||||
LL | for<'a> |x: &'a u8| *x + 1;
|
||||
| ------- ^
|
||||
| |
|
||||
| `for<...>` is here
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -6,7 +6,7 @@ use clippy_utils::ty::implements_trait;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
use rustc_hir::{BlockCheckMode, Expr, ExprKind};
|
||||
use rustc_hir::{BlockCheckMode, Closure, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -51,7 +51,7 @@ struct ExVisitor<'a, 'tcx> {
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||
if let ExprKind::Closure { body, .. } = expr.kind {
|
||||
if let ExprKind::Closure(&Closure { body, .. }) = expr.kind {
|
||||
// do not lint if the closure is called using an iterator (see #1141)
|
||||
if_chain! {
|
||||
if let Some(parent) = get_parent_expr(self.cx, expr);
|
||||
|
@ -5,7 +5,7 @@ use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind};
|
||||
use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, UintTy};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
|
||||
if count.ident.name == sym::count;
|
||||
if let ExprKind::MethodCall(filter, [filter_recv, filter_arg], _) = count_recv.kind;
|
||||
if filter.ident.name == sym!(filter);
|
||||
if let ExprKind::Closure { body, .. } = filter_arg.kind;
|
||||
if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind;
|
||||
let body = cx.tcx.hir().body(body);
|
||||
if let [param] = body.params;
|
||||
if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
|
||||
|
@ -7,7 +7,7 @@ use clippy_utils::{higher, is_adjusted, path_to_local, path_to_local_id};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Expr, ExprKind, Param, PatKind, Unsafety};
|
||||
use rustc_hir::{Closure, Expr, ExprKind, Param, PatKind, Unsafety};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
||||
use rustc_middle::ty::binding::BindingMode;
|
||||
@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
|
||||
return;
|
||||
}
|
||||
let body = match expr.kind {
|
||||
ExprKind::Closure { body, .. } => cx.tcx.hir().body(body),
|
||||
ExprKind::Closure(&Closure { body, .. }) => cx.tcx.hir().body(body),
|
||||
_ => return,
|
||||
};
|
||||
if body.value.span.from_expansion() {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::{higher, match_def_path, path_def_id, paths};
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind};
|
||||
use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
@ -159,7 +159,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
||||
}
|
||||
}
|
||||
if method.ident.name == sym!(flat_map) && args.len() == 2 {
|
||||
if let ExprKind::Closure { body, .. } = args[1].kind {
|
||||
if let ExprKind::Closure(&Closure { body, .. }) = args[1].kind {
|
||||
let body = cx.tcx.hir().body(body);
|
||||
return is_infinite(cx, &body.value);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use rustc_ast::ast;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, QPath};
|
||||
use rustc_hir::{BinOpKind, BorrowKind, Closure, Expr, ExprKind, HirId, Mutability, Pat, PatKind, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
@ -369,7 +369,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
},
|
||||
ExprKind::Closure { body, .. } => {
|
||||
ExprKind::Closure(&Closure { body, .. }) => {
|
||||
let body = self.cx.tcx.hir().body(body);
|
||||
self.visit_expr(&body.value);
|
||||
},
|
||||
|
@ -8,7 +8,7 @@ use clippy_utils::{
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp};
|
||||
use rustc_hir::{Closure, def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::adjustment::Adjust;
|
||||
use rustc_span::{symbol::sym, Symbol};
|
||||
@ -220,7 +220,7 @@ fn uses_iter<'tcx>(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tc
|
||||
if let Some(e) = e {
|
||||
self.visit_expr(e);
|
||||
}
|
||||
} else if let ExprKind::Closure { body: id, .. } = e.kind {
|
||||
} else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind {
|
||||
if is_res_used(self.cx, self.iter_expr.path, id) {
|
||||
self.uses_iter = true;
|
||||
}
|
||||
@ -260,7 +260,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
|
||||
if let Some(e) = e {
|
||||
self.visit_expr(e);
|
||||
}
|
||||
} else if let ExprKind::Closure { body: id, .. } = e.kind {
|
||||
} else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind {
|
||||
self.used_iter = is_res_used(self.cx, self.iter_expr.path, id);
|
||||
} else {
|
||||
walk_expr(self, e);
|
||||
@ -307,7 +307,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
|
||||
if let Some(e) = e {
|
||||
self.visit_expr(e);
|
||||
}
|
||||
} else if let ExprKind::Closure { body: id, .. } = e.kind {
|
||||
} else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind {
|
||||
self.used_after = is_res_used(self.cx, self.iter_expr.path, id);
|
||||
} else {
|
||||
walk_expr(self, e);
|
||||
|
@ -6,7 +6,7 @@ use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{
|
||||
AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
|
||||
AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
|
||||
IsAsync, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -177,7 +177,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>)
|
||||
if let Some(block_expr) = block.expr;
|
||||
if let Some(args) = match_function_call(cx, block_expr, &FUTURE_FROM_GENERATOR);
|
||||
if args.len() == 1;
|
||||
if let Expr{kind: ExprKind::Closure { body, .. }, ..} = args[0];
|
||||
if let Expr{kind: ExprKind::Closure(&Closure { body, .. }), ..} = args[0];
|
||||
let closure_body = cx.tcx.hir().body(body);
|
||||
if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block));
|
||||
then {
|
||||
|
@ -5,7 +5,7 @@ use clippy_utils::{is_lang_ctor, path_to_local_id};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem::{ResultErr, ResultOk};
|
||||
use rustc_hir::{Expr, ExprKind, PatKind};
|
||||
use rustc_hir::{Closure, Expr, ExprKind, PatKind};
|
||||
use rustc_lint::LintContext;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
@ -88,7 +88,7 @@ fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool {
|
||||
}
|
||||
}
|
||||
if_chain! {
|
||||
if let ExprKind::Closure { body, .. } = map_expr.kind;
|
||||
if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind;
|
||||
let body = cx.tcx.hir().body(body);
|
||||
if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind;
|
||||
if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind;
|
||||
|
@ -148,7 +148,7 @@ fn check_to_owned(
|
||||
|
||||
fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) {
|
||||
if let hir::ExprKind::MethodCall(_, [_, closure], _) = filter_expr.kind
|
||||
&& let hir::ExprKind::Closure{ body, ..} = closure.kind
|
||||
&& let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind
|
||||
&& let filter_body = cx.tcx.hir().body(body)
|
||||
&& let [filter_params] = filter_body.params
|
||||
&& let Some(sugg) = match filter_params.pat.kind {
|
||||
|
@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
|
||||
if method.ident.name == sym::map;
|
||||
let ty = cx.typeck_results().expr_ty(&args[0]);
|
||||
if is_type_diagnostic_item(cx, ty, sym::Option) || is_trait_method(cx, e, sym::Iterator);
|
||||
if let hir::ExprKind::Closure { body, .. } = args[1].kind;
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = args[1].kind;
|
||||
then {
|
||||
let closure_body = cx.tcx.hir().body(body);
|
||||
let closure_expr = peel_blocks(&closure_body.value);
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_hir::{CaptureBy, Expr, ExprKind, PatKind};
|
||||
use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
@ -119,12 +119,12 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore {
|
||||
if method.ident.as_str() == "map_err" && args.len() == 2 {
|
||||
// make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span
|
||||
// fields
|
||||
if let ExprKind::Closure {
|
||||
if let ExprKind::Closure(&Closure {
|
||||
capture_clause,
|
||||
body,
|
||||
fn_decl_span,
|
||||
..
|
||||
} = args[1].kind
|
||||
}) = args[1].kind
|
||||
{
|
||||
// check if this is by Reference (meaning there's no move statement)
|
||||
if capture_clause == CaptureBy::Ref {
|
||||
|
@ -169,7 +169,7 @@ fn unit_closure<'tcx>(
|
||||
expr: &hir::Expr<'_>,
|
||||
) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> {
|
||||
if_chain! {
|
||||
if let hir::ExprKind::Closure { fn_decl, body, .. } = expr.kind;
|
||||
if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = expr.kind;
|
||||
let body = cx.tcx.hir().body(body);
|
||||
let body_expr = &body.value;
|
||||
if fn_decl.inputs.len() == 1;
|
||||
|
@ -150,7 +150,7 @@ pub(crate) trait BindInsteadOfMap {
|
||||
}
|
||||
|
||||
match arg.kind {
|
||||
hir::ExprKind::Closure { body, fn_decl_span, .. } => {
|
||||
hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) => {
|
||||
let closure_body = cx.tcx.hir().body(body);
|
||||
let closure_expr = peel_blocks(&closure_body.value);
|
||||
|
||||
|
@ -6,7 +6,7 @@ use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Expr, ExprKind, PatKind, PathSegment, QPath, UnOp};
|
||||
use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
@ -22,8 +22,8 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
|
||||
hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
|
||||
segments.segments.last().unwrap().ident.name == method_name
|
||||
},
|
||||
hir::ExprKind::Closure { body, .. } => {
|
||||
let body = cx.tcx.hir().body(*body);
|
||||
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
|
||||
let body = cx.tcx.hir().body(body);
|
||||
let closure_expr = peel_blocks(&body.value);
|
||||
let arg_id = body.params[0].pat.hir_id;
|
||||
match closure_expr.kind {
|
||||
@ -106,7 +106,7 @@ pub(super) fn check<'tcx>(
|
||||
if is_trait_method(cx, map_recv, sym::Iterator);
|
||||
|
||||
// filter(|x| ...is_some())...
|
||||
if let ExprKind::Closure { body: filter_body_id, .. } = filter_arg.kind;
|
||||
if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind;
|
||||
let filter_body = cx.tcx.hir().body(filter_body_id);
|
||||
if let [filter_param] = filter_body.params;
|
||||
// optional ref pattern: `filter(|&x| ..)`
|
||||
@ -129,7 +129,7 @@ pub(super) fn check<'tcx>(
|
||||
if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
|
||||
|
||||
// ...map(|x| ...unwrap())
|
||||
if let ExprKind::Closure { body: map_body_id, .. } = map_arg.kind;
|
||||
if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind;
|
||||
let map_body = cx.tcx.hir().body(map_body_id);
|
||||
if let [map_param] = map_body.params;
|
||||
if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
|
||||
|
@ -51,7 +51,7 @@ pub(super) fn check<'tcx>(
|
||||
.map_or(false, |fun_def_id| {
|
||||
deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
|
||||
}),
|
||||
hir::ExprKind::Closure { body, .. } => {
|
||||
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
|
||||
let closure_body = cx.tcx.hir().body(body);
|
||||
let closure_expr = peel_blocks(&closure_body.value);
|
||||
|
||||
|
@ -71,7 +71,7 @@ pub(super) fn check<'tcx>(
|
||||
if is_option {
|
||||
let self_snippet = snippet(cx, recv.span, "..");
|
||||
if_chain! {
|
||||
if let hir::ExprKind::Closure { body, fn_decl_span, .. } = map_arg.kind;
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind;
|
||||
let arg_snippet = snippet(cx, fn_decl_span, "..");
|
||||
let body = cx.tcx.hir().body(body);
|
||||
if let Some((func, [arg_char])) = reduce_unit_expression(&body.value);
|
||||
|
@ -41,7 +41,7 @@ pub(super) fn check<'tcx>(
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let any_search_snippet = if_chain! {
|
||||
if search_method == "find";
|
||||
if let hir::ExprKind::Closure { body, .. } = search_arg.kind;
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind;
|
||||
let closure_body = cx.tcx.hir().body(body);
|
||||
if let Some(closure_arg) = closure_body.params.get(0);
|
||||
then {
|
||||
|
@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<
|
||||
return;
|
||||
}
|
||||
|
||||
if let hir::ExprKind::Closure { body, .. } = arg.kind {
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind {
|
||||
let body = cx.tcx.hir().body(body);
|
||||
let arg_id = body.params[0].pat.hir_id;
|
||||
let mutates_arg =
|
||||
|
@ -29,7 +29,7 @@ pub(super) fn check(
|
||||
) {
|
||||
if_chain! {
|
||||
// Extract the body of the closure passed to fold
|
||||
if let hir::ExprKind::Closure { body, .. } = acc.kind;
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind;
|
||||
let closure_body = cx.tcx.hir().body(body);
|
||||
let closure_expr = peel_blocks(&closure_body.value);
|
||||
|
||||
|
@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(
|
||||
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
|
||||
|
||||
if is_option || is_result {
|
||||
if let hir::ExprKind::Closure { body, .. } = arg.kind {
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind {
|
||||
let body = cx.tcx.hir().body(body);
|
||||
let body_expr = &body.value;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{
|
||||
intravisit::{walk_expr, Visitor},
|
||||
Expr, ExprKind, Stmt, StmtKind,
|
||||
Closure, Expr, ExprKind, Stmt, StmtKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
|
||||
if has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some();
|
||||
// Skip the lint if the body is not block because this is simpler than `for` loop.
|
||||
// e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop.
|
||||
if let ExprKind::Closure { body, .. } = for_each_arg.kind;
|
||||
if let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind;
|
||||
let body = cx.tcx.hir().body(body);
|
||||
if let ExprKind::Block(..) = body.value.kind;
|
||||
then {
|
||||
|
@ -11,7 +11,7 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
|
||||
use rustc_hir::intravisit::{walk_expr, walk_stmt, FnKind, Visitor};
|
||||
use rustc_hir::{
|
||||
Arm, Block, Body, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path, PathSegment,
|
||||
Arm, Closure, Block, Body, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path, PathSegment,
|
||||
QPath, Stmt, StmtKind, TyKind, UnOp,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -298,7 +298,7 @@ impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> {
|
||||
},
|
||||
ExprKind::Match(expr, arms, _) => self.visit_match(expr, arms),
|
||||
// since analysing the closure is not easy, just set all variables in it to side-effect
|
||||
ExprKind::Closure { body, .. } => {
|
||||
ExprKind::Closure(&Closure { body, .. }) => {
|
||||
let body = self.tcx.hir().body(body);
|
||||
self.visit_body(body);
|
||||
let vars = std::mem::take(&mut self.ret_vars);
|
||||
|
@ -69,7 +69,7 @@ impl EarlyLintPass for RedundantClosureCall {
|
||||
if_chain! {
|
||||
if let ast::ExprKind::Call(ref paren, _) = expr.kind;
|
||||
if let ast::ExprKind::Paren(ref closure) = paren.kind;
|
||||
if let ast::ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.kind;
|
||||
if let ast::ExprKind::Closure(_, _, _, _, ref decl, ref block, _) = closure.kind;
|
||||
then {
|
||||
let mut visitor = ReturnVisitor::new();
|
||||
visitor.visit_expr(block);
|
||||
|
@ -582,7 +582,7 @@ fn ident_difference_expr_with_base_location(
|
||||
| (Await(_), Await(_))
|
||||
| (Async(_, _, _), Async(_, _, _))
|
||||
| (Block(_, _), Block(_, _))
|
||||
| (Closure(_, _, _, _, _, _), Closure(_, _, _, _, _, _))
|
||||
| (Closure(_, _, _, _, _, _, _), Closure(_, _, _, _, _, _, _))
|
||||
| (Match(_, _), Match(_, _))
|
||||
| (Loop(_, _), Loop(_, _))
|
||||
| (ForLoop(_, _, _, _), ForLoop(_, _, _, _))
|
||||
|
@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
|
||||
use clippy_utils::{get_trait_def_id, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Expr, ExprKind, StmtKind};
|
||||
use rustc_hir::{Closure, Expr, ExprKind, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::{GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate};
|
||||
@ -116,7 +116,7 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
|
||||
|
||||
fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Span, Option<Span>)> {
|
||||
if_chain! {
|
||||
if let ExprKind::Closure { body, fn_decl_span, .. } = arg.kind;
|
||||
if let ExprKind::Closure(&Closure { body, fn_decl_span, .. }) = arg.kind;
|
||||
if let ty::Closure(_def_id, substs) = &cx.typeck_results().node_type(arg.hir_id).kind();
|
||||
let ret_ty = substs.as_closure().sig().output();
|
||||
let ty = cx.tcx.erase_late_bound_regions(ret_ty);
|
||||
|
@ -3,7 +3,7 @@ use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
|
||||
use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, subst::GenericArgKind};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -155,7 +155,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
|
||||
if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind;
|
||||
if let name = name_ident.ident.name.to_ident_string();
|
||||
if name == "sort_by" || name == "sort_unstable_by";
|
||||
if let [vec, Expr { kind: ExprKind::Closure{ body: closure_body_id, .. }, .. }] = args;
|
||||
if let [vec, Expr { kind: ExprKind::Closure(Closure { body: closure_body_id, .. }), .. }] = args;
|
||||
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::Vec);
|
||||
if let closure_body = cx.tcx.hir().body(*closure_body_id);
|
||||
if let &[
|
||||
|
@ -6,7 +6,7 @@ use rustc_ast::ast::{LitFloatType, LitKind};
|
||||
use rustc_ast::LitIntType;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{ArrayLen, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
|
||||
use rustc_hir::{ArrayLen, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
@ -466,13 +466,13 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
||||
self.expr(scrutinee);
|
||||
self.slice(arms, |arm| self.arm(arm));
|
||||
},
|
||||
ExprKind::Closure {
|
||||
ExprKind::Closure(&Closure {
|
||||
capture_clause,
|
||||
fn_decl,
|
||||
body: body_id,
|
||||
movability,
|
||||
..
|
||||
} => {
|
||||
}) => {
|
||||
let movability = OptionPat::new(movability.map(|m| format!("Movability::{m:?}")));
|
||||
|
||||
let ret_ty = match fn_decl.output {
|
||||
|
@ -168,8 +168,8 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
||||
(AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv),
|
||||
(Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp),
|
||||
(Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, eq_arm),
|
||||
(Closure(lc, la, lm, lf, lb, _), Closure(rc, ra, rm, rf, rb, _)) => {
|
||||
lc == rc && la.is_async() == ra.is_async() && lm == rm && eq_fn_decl(lf, rf) && eq_expr(lb, rb)
|
||||
(Closure(lb, lc, la, lm, lf, le, _), Closure(rb, rc, ra, rm, rf, re, _)) => {
|
||||
eq_closure_binder(lb, rb) && lc == rc && la.is_async() == ra.is_async() && lm == rm && eq_fn_decl(lf, rf) && eq_expr(le, re)
|
||||
},
|
||||
(Async(lc, _, lb), Async(rc, _, rb)) => lc == rc && eq_block(lb, rb),
|
||||
(Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt),
|
||||
@ -561,6 +561,15 @@ pub fn eq_fn_decl(l: &FnDecl, r: &FnDecl) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn eq_closure_binder(l: &ClosureBinder, r: &ClosureBinder) -> bool {
|
||||
match (l, r) {
|
||||
(ClosureBinder::NotPresent, ClosureBinder::NotPresent) => true,
|
||||
(ClosureBinder::For { generic_params: lp, .. }, ClosureBinder::For { generic_params: rp, .. }) =>
|
||||
lp.len() == rp.len() && std::iter::zip(lp.iter(), rp.iter()).all(|(l, r)| eq_generic_param(l, r)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eq_fn_ret_ty(l: &FnRetTy, r: &FnRetTy) -> bool {
|
||||
match (l, r) {
|
||||
(FnRetTy::Default(_), FnRetTy::Default(_)) => true,
|
||||
|
@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHasher;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::HirIdMap;
|
||||
use rustc_hir::{
|
||||
ArrayLen, BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
|
||||
ArrayLen, BinOpKind, Closure, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
|
||||
InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
|
||||
StmtKind, Ty, TyKind, TypeBinding,
|
||||
};
|
||||
@ -663,9 +663,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||
self.hash_expr(e);
|
||||
self.hash_ty(ty);
|
||||
},
|
||||
ExprKind::Closure {
|
||||
ExprKind::Closure(&Closure {
|
||||
capture_clause, body, ..
|
||||
} => {
|
||||
}) => {
|
||||
std::mem::discriminant(&capture_clause).hash(&mut self.s);
|
||||
// closures inherit TypeckResults
|
||||
self.hash_expr(&self.cx.tcx.hir().body(body).value);
|
||||
|
@ -79,10 +79,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
|
||||
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
|
||||
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
|
||||
use rustc_hir::{
|
||||
def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl,
|
||||
HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node,
|
||||
Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind,
|
||||
UnOp,
|
||||
def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination, Expr,
|
||||
ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource,
|
||||
Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
|
||||
TraitRef, TyKind, UnOp,
|
||||
};
|
||||
use rustc_lint::{LateContext, Level, Lint, LintContext};
|
||||
use rustc_middle::hir::place::PlaceBase;
|
||||
@ -1699,7 +1699,7 @@ pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'t
|
||||
_,
|
||||
&[
|
||||
Expr {
|
||||
kind: ExprKind::Closure { body, .. },
|
||||
kind: ExprKind::Closure(&Closure { body, .. }),
|
||||
..
|
||||
},
|
||||
],
|
||||
@ -1786,7 +1786,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool
|
||||
}
|
||||
|
||||
match expr.kind {
|
||||
ExprKind::Closure { body, .. } => is_body_identity_function(cx, cx.tcx.hir().body(body)),
|
||||
ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)),
|
||||
_ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)),
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use rustc_ast::{ast, token};
|
||||
use rustc_ast_pretty::pprust::token_kind_to_string;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{ExprKind, HirId, MutTy, TyKind};
|
||||
use rustc_hir::{Closure, ExprKind, HirId, MutTy, TyKind};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::{EarlyContext, LateContext, LintContext};
|
||||
use rustc_middle::hir::place::ProjectionKind;
|
||||
@ -790,7 +790,7 @@ pub struct DerefClosure {
|
||||
///
|
||||
/// note: this only works on single line immutable closures with exactly one input parameter.
|
||||
pub fn deref_closure_args<'tcx>(cx: &LateContext<'_>, closure: &'tcx hir::Expr<'_>) -> Option<DerefClosure> {
|
||||
if let hir::ExprKind::Closure { fn_decl, body, .. } = closure.kind {
|
||||
if let hir::ExprKind::Closure(&Closure { fn_decl, body, .. }) = closure.kind {
|
||||
let closure_body = cx.tcx.hir().body(body);
|
||||
// is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`)
|
||||
// a type annotation is present if param `kind` is different from `TyKind::Infer`
|
||||
|
@ -11,6 +11,7 @@ use crate::overflow::OverflowableItem;
|
||||
use crate::rewrite::{Rewrite, RewriteContext};
|
||||
use crate::shape::Shape;
|
||||
use crate::source_map::SpanUtils;
|
||||
use crate::types::rewrite_lifetime_param;
|
||||
use crate::utils::{last_line_width, left_most_sub_expr, stmt_expr, NodeIdExt};
|
||||
|
||||
// This module is pretty messy because of the rules around closures and blocks:
|
||||
@ -24,6 +25,7 @@ use crate::utils::{last_line_width, left_most_sub_expr, stmt_expr, NodeIdExt};
|
||||
// can change whether it is treated as an expression or statement.
|
||||
|
||||
pub(crate) fn rewrite_closure(
|
||||
binder: &ast::ClosureBinder,
|
||||
capture: ast::CaptureBy,
|
||||
is_async: &ast::Async,
|
||||
movability: ast::Movability,
|
||||
@ -36,7 +38,7 @@ pub(crate) fn rewrite_closure(
|
||||
debug!("rewrite_closure {:?}", body);
|
||||
|
||||
let (prefix, extra_offset) = rewrite_closure_fn_decl(
|
||||
capture, is_async, movability, fn_decl, body, span, context, shape,
|
||||
binder, capture, is_async, movability, fn_decl, body, span, context, shape,
|
||||
)?;
|
||||
// 1 = space between `|...|` and body.
|
||||
let body_shape = shape.offset_left(extra_offset)?;
|
||||
@ -227,6 +229,7 @@ fn rewrite_closure_block(
|
||||
|
||||
// Return type is (prefix, extra_offset)
|
||||
fn rewrite_closure_fn_decl(
|
||||
binder: &ast::ClosureBinder,
|
||||
capture: ast::CaptureBy,
|
||||
asyncness: &ast::Async,
|
||||
movability: ast::Movability,
|
||||
@ -236,6 +239,17 @@ fn rewrite_closure_fn_decl(
|
||||
context: &RewriteContext<'_>,
|
||||
shape: Shape,
|
||||
) -> Option<(String, usize)> {
|
||||
let binder = match binder {
|
||||
ast::ClosureBinder::For { generic_params, .. } if generic_params.is_empty() => {
|
||||
"for<> ".to_owned()
|
||||
}
|
||||
ast::ClosureBinder::For { generic_params, .. } => {
|
||||
let lifetime_str = rewrite_lifetime_param(context, shape, generic_params)?;
|
||||
format!("for<{lifetime_str}> ")
|
||||
}
|
||||
ast::ClosureBinder::NotPresent => "".to_owned(),
|
||||
};
|
||||
|
||||
let immovable = if movability == ast::Movability::Static {
|
||||
"static "
|
||||
} else {
|
||||
@ -250,7 +264,7 @@ fn rewrite_closure_fn_decl(
|
||||
// 4 = "|| {".len(), which is overconservative when the closure consists of
|
||||
// a single expression.
|
||||
let nested_shape = shape
|
||||
.shrink_left(immovable.len() + is_async.len() + mover.len())?
|
||||
.shrink_left(binder.len() + immovable.len() + is_async.len() + mover.len())?
|
||||
.sub_width(4)?;
|
||||
|
||||
// 1 = |
|
||||
@ -288,7 +302,7 @@ fn rewrite_closure_fn_decl(
|
||||
.tactic(tactic)
|
||||
.preserve_newline(true);
|
||||
let list_str = write_list(&item_vec, &fmt)?;
|
||||
let mut prefix = format!("{}{}{}|{}|", immovable, is_async, mover, list_str);
|
||||
let mut prefix = format!("{}{}{}{}|{}|", binder, immovable, is_async, mover, list_str);
|
||||
|
||||
if !ret_str.is_empty() {
|
||||
if prefix.contains('\n') {
|
||||
@ -312,8 +326,15 @@ pub(crate) fn rewrite_last_closure(
|
||||
expr: &ast::Expr,
|
||||
shape: Shape,
|
||||
) -> Option<String> {
|
||||
if let ast::ExprKind::Closure(capture, ref is_async, movability, ref fn_decl, ref body, _) =
|
||||
expr.kind
|
||||
if let ast::ExprKind::Closure(
|
||||
ref binder,
|
||||
capture,
|
||||
ref is_async,
|
||||
movability,
|
||||
ref fn_decl,
|
||||
ref body,
|
||||
_,
|
||||
) = expr.kind
|
||||
{
|
||||
let body = match body.kind {
|
||||
ast::ExprKind::Block(ref block, _)
|
||||
@ -326,7 +347,7 @@ pub(crate) fn rewrite_last_closure(
|
||||
_ => body,
|
||||
};
|
||||
let (prefix, extra_offset) = rewrite_closure_fn_decl(
|
||||
capture, is_async, movability, fn_decl, body, expr.span, context, shape,
|
||||
binder, capture, is_async, movability, fn_decl, body, expr.span, context, shape,
|
||||
)?;
|
||||
// If the closure goes multi line before its body, do not overflow the closure.
|
||||
if prefix.contains('\n') {
|
||||
|
@ -203,11 +203,17 @@ pub(crate) fn format_expr(
|
||||
Some("yield".to_string())
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Closure(capture, ref is_async, movability, ref fn_decl, ref body, _) => {
|
||||
closures::rewrite_closure(
|
||||
capture, is_async, movability, fn_decl, body, expr.span, context, shape,
|
||||
)
|
||||
}
|
||||
ast::ExprKind::Closure(
|
||||
ref binder,
|
||||
capture,
|
||||
ref is_async,
|
||||
movability,
|
||||
ref fn_decl,
|
||||
ref body,
|
||||
_,
|
||||
) => closures::rewrite_closure(
|
||||
binder, capture, is_async, movability, fn_decl, body, expr.span, context, shape,
|
||||
),
|
||||
ast::ExprKind::Try(..)
|
||||
| ast::ExprKind::Field(..)
|
||||
| ast::ExprKind::MethodCall(..)
|
||||
|
@ -1067,7 +1067,7 @@ pub(crate) fn can_be_overflowed_type(
|
||||
}
|
||||
|
||||
/// Returns `None` if there is no `LifetimeDef` in the given generic parameters.
|
||||
fn rewrite_lifetime_param(
|
||||
pub(crate) fn rewrite_lifetime_param(
|
||||
context: &RewriteContext<'_>,
|
||||
shape: Shape,
|
||||
generic_params: &[ast::GenericParam],
|
||||
|
@ -479,7 +479,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
|
||||
| ast::ExprKind::Binary(_, _, ref expr)
|
||||
| ast::ExprKind::Index(_, ref expr)
|
||||
| ast::ExprKind::Unary(_, ref expr)
|
||||
| ast::ExprKind::Closure(_, _, _, _, ref expr, _)
|
||||
| ast::ExprKind::Closure(_, _, _, _, _, ref expr, _)
|
||||
| ast::ExprKind::Try(ref expr)
|
||||
| ast::ExprKind::Yield(Some(ref expr)) => is_block_expr(context, expr, repr),
|
||||
// This can only be a string lit
|
||||
|
@ -51,6 +51,16 @@ fn main() {
|
||||
"--emit=dep-info"
|
||||
} else { a }
|
||||
});
|
||||
|
||||
for<> || -> () {};
|
||||
for< >|| -> () {};
|
||||
for<
|
||||
> || -> () {};
|
||||
|
||||
for< 'a
|
||||
,'b,
|
||||
'c > |_: &'a (), _: &'b (), _: &'c ()| -> () {};
|
||||
|
||||
}
|
||||
|
||||
fn issue311() {
|
||||
|
@ -71,6 +71,12 @@ fn main() {
|
||||
a
|
||||
}
|
||||
});
|
||||
|
||||
for<> || -> () {};
|
||||
for<> || -> () {};
|
||||
for<> || -> () {};
|
||||
|
||||
for<'a, 'b, 'c> |_: &'a (), _: &'b (), _: &'c ()| -> () {};
|
||||
}
|
||||
|
||||
fn issue311() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user