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:
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user