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)
}
}
// `static |_task_context| -> <ret_ty> { body }`:
let generator_kind = hir::ExprKind::Closure {
+ binder: &hir::ClosureBinder::Default,
capture_clause,
bound_generic_params: &[],
fn_decl,
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;
(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,
}
}
}
+ 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,
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) };
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,
/// 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>,
}
}
+/// 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,
FnKind::ItemFn(_, generics, ..) => {
visitor.visit_generics(generics);
}
- FnKind::Method(..) | FnKind::Closure => {}
+ FnKind::Closure | FnKind::Method(..) => {}
}
}
walk_list!(visitor, visit_arm, arms);
}
ExprKind::Closure {
+ binder: _,
bound_generic_params,
ref fn_decl,
body,
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);
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;
self.bclose(expr.span);
}
hir::ExprKind::Closure {
+ binder,
capture_clause,
bound_generic_params,
fn_decl,
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);
}
}
+ 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,
self.check_id(closure_id);
}
}
+
run_early_pass!(self, check_fn_post, fk, span, id);
}
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),
);
}
}
+ 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);
});
}
// 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));
}
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
(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,
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
}
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
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
}
-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 ()| {};
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`
}
-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
= 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
= 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`.
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 }
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
|
= 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 {}
| ^^^^^^^^^
= 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`.