1
Fork 0

Refactor visit_fn.

This commit is contained in:
Camille GILLOT 2022-06-05 18:24:22 +02:00
parent 80c6a1f275
commit 237e267b80
2 changed files with 97 additions and 66 deletions

View file

@ -746,36 +746,43 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
self.diagnostic_metadata.current_function = Some((fn_kind, sp)); self.diagnostic_metadata.current_function = Some((fn_kind, sp));
} }
debug!("(resolving function) entering function"); debug!("(resolving function) entering function");
let declaration = fn_kind.decl();
// Create a value rib for the function. // Create a value rib for the function.
self.with_rib(ValueNS, rib_kind, |this| { self.with_rib(ValueNS, rib_kind, |this| {
// Create a label rib for the function. // Create a label rib for the function.
this.with_label_rib(FnItemRibKind, |this| { this.with_label_rib(FnItemRibKind, |this| {
let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id()); match fn_kind {
FnKind::Fn(_, _, sig, _, generics, body) => {
if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
this.visit_generics(generics); this.visit_generics(generics);
}
if let Some(async_node_id) = async_node_id { let declaration = &sig.decl;
// In `async fn`, argument-position elided lifetimes let async_node_id = sig.header.asyncness.opt_return_id();
// must be transformed into fresh generic parameters so that
// they can be applied to the opaque `impl Trait` return type. // Argument-position elided lifetimes must be transformed into fresh
// generic parameters. This is especially useful for `async fn`, where
// these fresh generic parameters can be applied to the opaque `impl Trait`
// return type.
this.with_lifetime_rib( this.with_lifetime_rib(
LifetimeRibKind::AnonymousCreateParameter(fn_id), if async_node_id.is_some() {
|this| { LifetimeRibKind::AnonymousCreateParameter(fn_id)
// Add each argument to the rib. } else {
this.resolve_params(&declaration.inputs) LifetimeRibKind::AnonymousPassThrough(fn_id, false)
}, },
// Add each argument to the rib.
|this| this.resolve_params(&declaration.inputs),
); );
// Construct the list of in-scope lifetime parameters for async lowering. // Construct the list of in-scope lifetime parameters for async lowering.
// We include all lifetime parameters, either named or "Fresh". // We include all lifetime parameters, either named or "Fresh".
// The order of those parameters does not matter, as long as it is // The order of those parameters does not matter, as long as it is
// deterministic. // deterministic.
let mut extra_lifetime_params = if let Some(async_node_id) = async_node_id {
this.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default(); let mut extra_lifetime_params = this
.r
.extra_lifetime_params_map
.get(&fn_id)
.cloned()
.unwrap_or_default();
for rib in this.lifetime_ribs.iter().rev() { for rib in this.lifetime_ribs.iter().rev() {
extra_lifetime_params.extend( extra_lifetime_params.extend(
rib.bindings rib.bindings
@ -784,9 +791,9 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
); );
match rib.kind { match rib.kind {
LifetimeRibKind::Item => break, LifetimeRibKind::Item => break,
LifetimeRibKind::AnonymousCreateParameter(id) => { LifetimeRibKind::AnonymousCreateParameter(binder) => {
if let Some(earlier_fresh) = if let Some(earlier_fresh) =
this.r.extra_lifetime_params_map.get(&id) this.r.extra_lifetime_params_map.get(&binder)
{ {
extra_lifetime_params.extend(earlier_fresh); extra_lifetime_params.extend(earlier_fresh);
} }
@ -794,23 +801,48 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
_ => {} _ => {}
} }
} }
this.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params); this.r
.extra_lifetime_params_map
.insert(async_node_id, extra_lifetime_params);
}
this.with_lifetime_rib( this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(async_node_id, true), LifetimeRibKind::AnonymousPassThrough(
// For async fn, the return type appears inside a custom
// `impl Future` RPIT, so we override the binder's id.
async_node_id.unwrap_or(fn_id),
true,
),
|this| visit::walk_fn_ret_ty(this, &declaration.output), |this| visit::walk_fn_ret_ty(this, &declaration.output),
); );
} else {
// Add each argument to the rib. if let Some(body) = body {
// Ignore errors in function bodies if this is rustdoc
// Be sure not to set this until the function signature has been resolved.
let previous_state = replace(&mut this.in_func_body, true);
// Resolve the function body, potentially inside the body of an async closure
this.with_lifetime_rib( this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(fn_id, false), LifetimeRibKind::AnonymousPassThrough(fn_id, false),
|this| this.visit_block(body),
);
debug!("(resolving function) leaving function");
this.in_func_body = previous_state;
}
}
FnKind::Closure(declaration, body) => {
// Do not attempt to create generic lifetime parameters.
// FIXME: Revisit this decision once `for<>` bounds on closures become a
// thing.
this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(fn_id, false),
// Add each argument to the rib.
|this| this.resolve_params(&declaration.inputs), |this| this.resolve_params(&declaration.inputs),
); );
this.with_lifetime_rib( this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(fn_id, true), LifetimeRibKind::AnonymousPassThrough(fn_id, true),
|this| visit::walk_fn_ret_ty(this, &declaration.output), |this| visit::walk_fn_ret_ty(this, &declaration.output),
); );
};
// Ignore errors in function bodies if this is rustdoc // Ignore errors in function bodies if this is rustdoc
// Be sure not to set this until the function signature has been resolved. // Be sure not to set this until the function signature has been resolved.
@ -818,14 +850,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
// Resolve the function body, potentially inside the body of an async closure // Resolve the function body, potentially inside the body of an async closure
this.with_lifetime_rib( this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(fn_id, false), LifetimeRibKind::AnonymousPassThrough(fn_id, false),
|this| match fn_kind { |this| this.visit_expr(body),
FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
FnKind::Closure(_, body) => this.visit_expr(body),
},
); );
debug!("(resolving function) leaving function"); debug!("(resolving function) leaving function");
this.in_func_body = previous_state; this.in_func_body = previous_state;
}
}
}) })
}); });
self.diagnostic_metadata.current_function = previous_value; self.diagnostic_metadata.current_function = previous_value;

View file

@ -11,7 +11,7 @@ LL | | }
| |
= note: expected fn pointer `fn(&mut RepeatMut<'a, T>) -> Option<_>` = note: expected fn pointer `fn(&mut RepeatMut<'a, T>) -> Option<_>`
found fn pointer `fn(&'a mut RepeatMut<'a, T>) -> Option<_>` found fn pointer `fn(&'a mut RepeatMut<'a, T>) -> Option<_>`
note: the anonymous lifetime #1 defined here... note: the anonymous lifetime as defined here...
--> $DIR/issue-37884.rs:6:5 --> $DIR/issue-37884.rs:6:5
| |
LL | fn next(&'a mut self) -> Option<Self::Item> LL | fn next(&'a mut self) -> Option<Self::Item>