]> git.lizzy.rs Git - rust.git/commitdiff
Lower closure binders to hir & properly check them
authorMaybe Waffle <waffle.lapkin@gmail.com>
Tue, 12 Jul 2022 09:34:24 +0000 (13:34 +0400)
committerMaybe Waffle <waffle.lapkin@gmail.com>
Tue, 12 Jul 2022 17:00:03 +0000 (21:00 +0400)
16 files changed:
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_lint/src/early.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/lifetimes.rs
src/test/ui/closures/binder/async-closure-with-binder.rs
src/test/ui/closures/binder/async-closure-with-binder.stderr
src/test/ui/closures/binder/implicit-return.rs
src/test/ui/closures/binder/implicit-return.stderr
src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.rs
src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.stderr
src/test/ui/parser/recover-quantified-closure.rs
src/test/ui/parser/recover-quantified-closure.stderr

index 327fc505e99a44d0c39a5b52b5a05a683b7d1aa6..3f830acbf27a61f139fb4aa79f5edea564ba70e8 100644 (file)
@@ -642,7 +642,7 @@ pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics
 pub fn walk_closure_binder<'a, V: Visitor<'a>>(visitor: &mut V, binder: &'a ClosureBinder) {
     match binder {
         ClosureBinder::NotPresent => {}
-        ClosureBinder::For { span: _, generic_params } => {
+        ClosureBinder::For { generic_params, span: _ } => {
             walk_list!(visitor, visit_generic_param, generic_params)
         }
     }
index 7a35660b0af2de5988bbfb710316fbbf4590f29c..995dc6aab5561913b025d6f1668997cf60beff5b 100644 (file)
@@ -609,6 +609,7 @@ pub(super) fn make_async_expr(
 
         // `static |_task_context| -> <ret_ty> { body }`:
         let generator_kind = hir::ExprKind::Closure {
+            binder: &hir::ClosureBinder::Default,
             capture_clause,
             bound_generic_params: &[],
             fn_decl,
@@ -842,15 +843,9 @@ fn lower_expr_closure(
         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 (binder_clause, generic_params) = self.lower_closure_binder(binder);
 
-        let (body, generator_option) = self.with_new_scopes(move |this| {
+        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;
@@ -865,15 +860,16 @@ fn lower_expr_closure(
             (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 {
+                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,
             }
@@ -918,6 +914,21 @@ fn generator_movability_for_fn(
         }
     }
 
+    fn lower_closure_binder<'c>(
+        &mut self,
+        binder: &'c ClosureBinder,
+    ) -> (&'hir 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)
+            }
+        };
+
+        (self.arena.alloc(binder), params)
+    }
+
     fn lower_expr_async_closure(
         &mut self,
         binder: &ClosureBinder,
@@ -928,17 +939,15 @@ fn lower_expr_async_closure(
         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();
+            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) };
 
@@ -976,13 +985,14 @@ fn lower_expr_async_closure(
             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 {
+                binder: binder_clause,
                 capture_clause,
                 bound_generic_params,
                 fn_decl,
index d60ac330ed1bb9d9c909a3dbe6e011369611e5c3..2252dfd683a418065b379a779487c30c82d2c5c5 100644 (file)
@@ -1931,6 +1931,7 @@ pub enum ExprKind<'hir> {
     /// This may also be a generator literal or an `async block` as indicated by the
     /// `Option<Movability>`.
     Closure {
+        binder: &'hir ClosureBinder,
         capture_clause: CaptureBy,
         bound_generic_params: &'hir [GenericParam<'hir>],
         fn_decl: &'hir FnDecl<'hir>,
@@ -2715,6 +2716,17 @@ pub fn span(&self) -> Span {
     }
 }
 
+/// 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,
index 531d9f14040217c86c2580c1fe08ae187a561665..6eceef56b47d6c7ef237b80f9fdc6466fecbcbd2 100644 (file)
@@ -925,7 +925,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(..) => {}
     }
 }
 
@@ -1145,6 +1145,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             walk_list!(visitor, visit_arm, arms);
         }
         ExprKind::Closure {
+            binder: _,
             bound_generic_params,
             ref fn_decl,
             body,
@@ -1153,7 +1154,13 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             movability: _,
         } => {
             walk_list!(visitor, visit_generic_param, bound_generic_params);
-            visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
+            visitor.visit_fn(
+                FnKind::Closure,
+                fn_decl,
+                body,
+                expression.span,
+                expression.hir_id,
+            )
         }
         ExprKind::Block(ref block, ref opt_label) => {
             walk_list!(visitor, visit_label, opt_label);
index 50acb0270b0bee7fe6199c2f2feff4d928710d6c..5453f4a8c9295817e068509486cecac33c916c7a 100644 (file)
@@ -6,6 +6,7 @@
 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;
@@ -1441,6 +1442,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr<'_>) {
                 self.bclose(expr.span);
             }
             hir::ExprKind::Closure {
+                binder,
                 capture_clause,
                 bound_generic_params,
                 fn_decl,
@@ -1448,7 +1450,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr<'_>) {
                 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);
@@ -2033,6 +2035,42 @@ pub fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
         }
     }
 
+    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,
index 6c9638400b299a125e1f58caf9ac7b36791e38bc..87cb2651dd31403edfe2a38651c5f5e8319309ce 100644 (file)
@@ -154,6 +154,7 @@ fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, span: Span, id: ast::NodeId) {
                 self.check_id(closure_id);
             }
         }
+
         run_early_pass!(self, check_fn_post, fk, span, id);
     }
 
index caf6f8c8392320bfb19ce5cde38f22a646a9d2d6..80186650fe869d26dcf42fff4e32631f11a5b49b 100644 (file)
@@ -844,19 +844,30 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
                             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),
                         );
 
@@ -891,6 +902,18 @@ fn visit_generics(&mut self, generics: &'ast Generics) {
         }
     }
 
+    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);
@@ -3515,6 +3538,18 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
                 });
             }
             // 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::Function,
+                        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));
index 557dbecfabe097bb3b00aa10e59571776b91bcb6..547255498a0962a61ae5c1db4f8168b4daf44afe 100644 (file)
@@ -571,7 +571,51 @@ fn visit_nested_body(&mut self, body: hir::BodyId) {
     }
 
     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 { 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 +628,9 @@ fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
                         (pair, r)
                     })
                     .unzip();
+
+            // FIXME: missing_named_lifetime_spots
+
             self.map.late_bound_vars.insert(e.hir_id, binders);
             let scope = Scope::Binder {
                 hir_id: e.hir_id,
index b9ecbd9e5d6769357a1852b87918121bfb116b10..4fa599d37cbd170005aa9e9e94366a2267ea8df9 100644 (file)
@@ -4,4 +4,5 @@
 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
 }
index 46420a177522737e1fd18957da09607799859e4f..1d4628b1a494a726b43c4d85d9162f0a8bccb49a 100644 (file)
@@ -4,5 +4,13 @@ error: `for<...>` binders on `async` closures are not currently supported
 LL |     for<'a> async || ();
    |     ^^^^^^^
 
-error: aborting due to previous error
+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
 
index 3aefbdcb299b4495232700557fcb90b16684c5d5..d34e5721d919b6d6aead9fdad98ea9fc73b1410f 100644 (file)
@@ -2,5 +2,5 @@
 
 fn main() {
     let _f = for<'a> |_: &'a ()| {};
-    //~^ implicit return type is forbidden when `for<...>` is present
+    //~^ implicit types in closure signatures are forbidden when `for<...>` is present
 }
index 022a4e027b650d42fa300c323ded87935753fd8f..5bfb97113344a1ea4896a216e93105339ab50352 100644 (file)
@@ -1,4 +1,4 @@
-error: implicit return type is forbidden when `for<...>` is present
+error: implicit types in closure signatures are forbidden when `for<...>` is present
   --> $DIR/implicit-return.rs:4:34
    |
 LL |     let _f = for<'a> |_: &'a ()| {};
index 1e2090186a698802f7cdcfe8b1423824ecce9111..b0b494fa3ff13240a558a4a215f55f43013c4201 100644 (file)
@@ -1,12 +1,8 @@
 fn main() {
-    for<> || {};
+    for<> || -> () {};
     //~^ ERROR `for<...>` binders for closures are experimental
-    //~^^ ERROR `for<...>` binders for closures are not yet supported
-    for<'a> || {};
+    for<'a> || -> () {};
     //~^ ERROR `for<...>` binders for closures are experimental
-    //~^^ ERROR `for<...>` binders for closures are not yet supported
-    for<'a, 'b> |_: &'a ()| {};
+    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`
 }
index 77ce6f9f2d635460096fe75838b3002b6869f855..aea5cfeed0705825ce554186d4b2c91aafb5c28b 100644 (file)
@@ -1,16 +1,7 @@
-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<> || {};
+LL |     for<> || -> () {};
    |     ^^^^^
    |
    = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
@@ -18,9 +9,9 @@ LL |     for<> || {};
    = help: consider removing `for<...>`
 
 error[E0658]: `for<...>` binders for closures are experimental
-  --> $DIR/feature-gate-closure_lifetime_binder.rs:5:5
+  --> $DIR/feature-gate-closure_lifetime_binder.rs:4:5
    |
-LL |     for<'a> || {};
+LL |     for<'a> || -> () {};
    |     ^^^^^^^
    |
    = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
@@ -28,40 +19,15 @@ LL |     for<'a> || {};
    = help: consider removing `for<...>`
 
 error[E0658]: `for<...>` binders for closures are experimental
-  --> $DIR/feature-gate-closure_lifetime_binder.rs:8:5
+  --> $DIR/feature-gate-closure_lifetime_binder.rs:6:5
    |
-LL |     for<'a, 'b> |_: &'a ()| {};
+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
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0261, E0658.
-For more information about an error, try `rustc --explain E0261`.
+For more information about this error, try `rustc --explain E0658`.
index a2bb7fde8ff19b0dcc565cb749b3a3575326e2e3..10af39b70074882ef906f592ac57975f4df7beba 100644 (file)
@@ -1,8 +1,7 @@
 fn main() {
     for<'a> |x: &'a u8| *x + 1;
-    //~^ ERROR use of undeclared lifetime name `'a`
-    //~^^ ERROR `for<...>` binders for closures are experimental
-    //~^^^ ERROR `for<...>` binders for closures are not yet supported
+    //~^ ERROR `for<...>` binders for closures are experimental
+    //~^^ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
 }
 
 enum Foo { Bar }
index 168307ea65a6b759ebab78fca7661c4b8bb1c8d6..39eec80f658ad9344ab64a8091c32381806b2b81 100644 (file)
@@ -1,17 +1,9 @@
 error: expected one of `move`, `static`, `|`, or `||`, found `::`
-  --> $DIR/recover-quantified-closure.rs:10:14
+  --> $DIR/recover-quantified-closure.rs:9:14
    |
 LL |     for <Foo>::Bar in x {}
    |              ^^ expected one of `move`, `static`, `|`, or `||`
 
-error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/recover-quantified-closure.rs:2:18
-   |
-LL | fn main() {
-   |        - help: consider introducing lifetime `'a` here: `<'a>`
-LL |     for<'a> |x: &'a u8| *x + 1;
-   |                  ^^ undeclared lifetime
-
 error[E0658]: `for<...>` binders for closures are experimental
   --> $DIR/recover-quantified-closure.rs:2:5
    |
@@ -23,7 +15,7 @@ LL |     for<'a> |x: &'a u8| *x + 1;
    = help: consider removing `for<...>`
 
 error[E0658]: `for<...>` binders for closures are experimental
-  --> $DIR/recover-quantified-closure.rs:10:5
+  --> $DIR/recover-quantified-closure.rs:9:5
    |
 LL |     for <Foo>::Bar in x {}
    |     ^^^^^^^^^
@@ -32,15 +24,14 @@ LL |     for <Foo>::Bar in x {}
    = 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/recover-quantified-closure.rs:2:5
+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;
-   |     ^^^^^^^
-   |
-   = help: consider removing `for<...>`
+   |     -------             ^
+   |     |
+   |     `for<...>` is here
 
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0261, E0658.
-For more information about an error, try `rustc --explain E0261`.
+For more information about this error, try `rustc --explain E0658`.