diff options
| author | Maybe Waffle <waffle.lapkin@gmail.com> | 2022-06-02 20:15:05 +0400 |
|---|---|---|
| committer | Maybe Waffle <waffle.lapkin@gmail.com> | 2022-07-12 16:25:16 +0400 |
| commit | 40ae7b5b8e09da657b62bc849b8bcdf99a1cb210 (patch) | |
| tree | f2a08c2651b0cb786a37697ee7806b272c01bb1d | |
| parent | fbdb07f4e7f4666085aec4b1ed2fd05817dc42cf (diff) | |
| download | rust-40ae7b5b8e09da657b62bc849b8bcdf99a1cb210.tar.gz rust-40ae7b5b8e09da657b62bc849b8bcdf99a1cb210.zip | |
Parse closure binders
This is first step in implementing RFC 3216. - Parse `for<'a>` before closures in ast - Error in lowering - Add `closure_lifetime_binder` feature
24 files changed, 287 insertions, 38 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f705d004422..ac2328a5824 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -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)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 85bb5296486..d933ea2da9e 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -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); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 2ce8590d771..327fc505e99 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -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 { span: _, generic_params } => { + 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); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 9e02e7ed3b9..7a35660b0af 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -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, @@ -831,6 +834,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_closure( &mut self, + binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, movability: Movability, @@ -838,6 +842,14 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Expr, fn_decl_span: Span, ) -> hir::ExprKind<'hir> { + // FIXME(waffle): lower binder + if let &ClosureBinder::For { span, .. } = binder { + self.sess + .struct_span_err(span, "`for<...>` binders for closures are not yet supported") + .help("consider removing `for<...>`") + .emit(); + } + let (body, generator_option) = self.with_new_scopes(move |this| { let prev = this.current_item; this.current_item = Some(fn_decl_span); @@ -908,6 +920,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_async_closure( &mut self, + binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, inner_closure_id: NodeId, @@ -915,6 +928,17 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Expr, fn_decl_span: Span, ) -> hir::ExprKind<'hir> { + // FIXME(waffle): lower binder + if let &ClosureBinder::For { span, .. } = binder { + self.sess + .struct_span_err( + span, + "`for<...>` binders for async closures are not yet supported", + ) + .help("consider removing `for<...>`") + .emit(); + } + let outer_decl = FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 3942062656f..f284bf4650a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -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( _, _, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index fd2dd6cf6c7..e69f85eacf7 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -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"); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 9f44f1b6cc2..ead38caee28 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -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"), diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 9e50d33486c..01152ff7df5 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -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 diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 74e9bbeeeaf..fa3e2a4a5b8 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -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, diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index b54f0ef361a..8d19ae2e3f4 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -331,6 +331,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. diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 5de35dc0856..6c9638400b2 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -218,7 +218,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), _ => {} } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 2c43563b104..c793e734224 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -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) @@ -2094,29 +2090,21 @@ 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>> { + /// 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 _ = 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(); + 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); - Ok(self.mk_expr_err(lo.to(closure.span))) - } + self.sess.gated_spans.gate(sym::closure_lifetime_binder, 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; + 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 }; @@ -2160,7 +2148,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, ); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 52706fbb9e6..66641fb2cb2 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -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); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 640d13ea435..caf6f8c8392 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3495,7 +3495,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: diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9b6967621f1..4505dd64a10 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -459,6 +459,7 @@ symbols! { clone_closures, clone_from, closure, + closure_lifetime_binder, closure_to_fn_coercion, closure_track_caller, cmp, diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index a37d3a32571..a679b7b4e19 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -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, diff --git a/src/test/ui/closures/binder/async-closure-with-binder.rs b/src/test/ui/closures/binder/async-closure-with-binder.rs new file mode 100644 index 00000000000..b9ecbd9e5d6 --- /dev/null +++ b/src/test/ui/closures/binder/async-closure-with-binder.rs @@ -0,0 +1,7 @@ +// edition:2021 +#![feature(closure_lifetime_binder)] +#![feature(async_closure)] +fn main() { + for<'a> async || (); + //~^ ERROR `for<...>` binders on `async` closures are not currently supported +} diff --git a/src/test/ui/closures/binder/async-closure-with-binder.stderr b/src/test/ui/closures/binder/async-closure-with-binder.stderr new file mode 100644 index 00000000000..46420a17752 --- /dev/null +++ b/src/test/ui/closures/binder/async-closure-with-binder.stderr @@ -0,0 +1,8 @@ +error: `for<...>` binders on `async` closures are not currently supported + --> $DIR/async-closure-with-binder.rs:5:5 + | +LL | for<'a> async || (); + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/closures/binder/implicit-return.rs b/src/test/ui/closures/binder/implicit-return.rs new file mode 100644 index 00000000000..3aefbdcb299 --- /dev/null +++ b/src/test/ui/closures/binder/implicit-return.rs @@ -0,0 +1,6 @@ +#![feature(closure_lifetime_binder)] + +fn main() { + let _f = for<'a> |_: &'a ()| {}; + //~^ implicit return type is forbidden when `for<...>` is present +} diff --git a/src/test/ui/closures/binder/implicit-return.stderr b/src/test/ui/closures/binder/implicit-return.stderr new file mode 100644 index 00000000000..022a4e027b6 --- /dev/null +++ b/src/test/ui/closures/binder/implicit-return.stderr @@ -0,0 +1,10 @@ +error: implicit return type is 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 + diff --git a/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.rs b/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.rs new file mode 100644 index 00000000000..b476dd50cc9 --- /dev/null +++ b/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.rs @@ -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` +} diff --git a/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.stderr b/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.stderr new file mode 100644 index 00000000000..1381acc15ca --- /dev/null +++ b/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.stderr @@ -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`. diff --git a/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.rs b/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.rs new file mode 100644 index 00000000000..1e2090186a6 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.rs @@ -0,0 +1,12 @@ +fn main() { + for<> || {}; + //~^ ERROR `for<...>` binders for closures are experimental + //~^^ ERROR `for<...>` binders for closures are not yet supported + for<'a> || {}; + //~^ ERROR `for<...>` binders for closures are experimental + //~^^ ERROR `for<...>` binders for closures are not yet supported + for<'a, 'b> |_: &'a ()| {}; + //~^ ERROR `for<...>` binders for closures are experimental + //~^^ ERROR `for<...>` binders for closures are not yet supported + //~^^^ ERROR use of undeclared lifetime name `'a` +} diff --git a/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.stderr b/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.stderr new file mode 100644 index 00000000000..77ce6f9f2d6 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.stderr @@ -0,0 +1,67 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/feature-gate-closure_lifetime_binder.rs:8:22 + | +LL | fn main() { + | - help: consider introducing lifetime `'a` here: `<'a>` +... +LL | for<'a, 'b> |_: &'a ()| {}; + | ^^ undeclared lifetime + +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:5: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:8: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: `for<...>` binders for closures are not yet supported + --> $DIR/feature-gate-closure_lifetime_binder.rs:2:5 + | +LL | for<> || {}; + | ^^^^^ + | + = help: consider removing `for<...>` + +error: `for<...>` binders for closures are not yet supported + --> $DIR/feature-gate-closure_lifetime_binder.rs:5:5 + | +LL | for<'a> || {}; + | ^^^^^^^ + | + = help: consider removing `for<...>` + +error: `for<...>` binders for closures are not yet supported + --> $DIR/feature-gate-closure_lifetime_binder.rs:8:5 + | +LL | for<'a, 'b> |_: &'a ()| {}; + | ^^^^^^^^^^^ + | + = help: consider removing `for<...>` + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0261, E0658. +For more information about an error, try `rustc --explain E0261`. |
