about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2022-06-05 18:24:22 +0200
committerCamille GILLOT <gillot.camille@gmail.com>2022-06-18 16:59:19 +0200
commit237e267b8050bac6e24d412f0d577c5ca9d57ca1 (patch)
tree0f71a884a28356da3fc5a7fc454185f178b5a2d9
parent80c6a1f275b8cc03773f716fc470889bf344ec03 (diff)
downloadrust-237e267b8050bac6e24d412f0d577c5ca9d57ca1.tar.gz
rust-237e267b8050bac6e24d412f0d577c5ca9d57ca1.zip
Refactor visit_fn.
-rw-r--r--compiler/rustc_resolve/src/late.rs161
-rw-r--r--src/test/ui/issues/issue-37884.stderr2
2 files changed, 97 insertions, 66 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 8d454aeff99..fce24049505 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -746,86 +746,117 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
             self.diagnostic_metadata.current_function = Some((fn_kind, sp));
         }
         debug!("(resolving function) entering function");
-        let declaration = fn_kind.decl();
 
         // Create a value rib for the function.
         self.with_rib(ValueNS, rib_kind, |this| {
             // Create a label rib for the function.
             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) => {
+                        this.visit_generics(generics);
 
-                if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
-                    this.visit_generics(generics);
-                }
+                        let declaration = &sig.decl;
+                        let async_node_id = sig.header.asyncness.opt_return_id();
 
-                if let Some(async_node_id) = async_node_id {
-                    // In `async fn`, argument-position elided lifetimes
-                    // must be transformed into fresh generic parameters so that
-                    // they can be applied to the opaque `impl Trait` return type.
-                    this.with_lifetime_rib(
-                        LifetimeRibKind::AnonymousCreateParameter(fn_id),
-                        |this| {
+                        // 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(
+                            if async_node_id.is_some() {
+                                LifetimeRibKind::AnonymousCreateParameter(fn_id)
+                            } else {
+                                LifetimeRibKind::AnonymousPassThrough(fn_id, false)
+                            },
                             // Add each argument to the rib.
-                            this.resolve_params(&declaration.inputs)
-                        },
-                    );
-
-                    // Construct the list of in-scope lifetime parameters for async lowering.
-                    // We include all lifetime parameters, either named or "Fresh".
-                    // The order of those parameters does not matter, as long as it is
-                    // deterministic.
-                    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() {
-                        extra_lifetime_params.extend(
-                            rib.bindings
-                                .iter()
-                                .map(|(&ident, &(node_id, res))| (ident, node_id, res)),
+                            |this| this.resolve_params(&declaration.inputs),
                         );
-                        match rib.kind {
-                            LifetimeRibKind::Item => break,
-                            LifetimeRibKind::AnonymousCreateParameter(id) => {
-                                if let Some(earlier_fresh) =
-                                    this.r.extra_lifetime_params_map.get(&id)
-                                {
-                                    extra_lifetime_params.extend(earlier_fresh);
+
+                        // Construct the list of in-scope lifetime parameters for async lowering.
+                        // We include all lifetime parameters, either named or "Fresh".
+                        // The order of those parameters does not matter, as long as it is
+                        // deterministic.
+                        if let Some(async_node_id) = async_node_id {
+                            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() {
+                                extra_lifetime_params.extend(
+                                    rib.bindings
+                                        .iter()
+                                        .map(|(&ident, &(node_id, res))| (ident, node_id, res)),
+                                );
+                                match rib.kind {
+                                    LifetimeRibKind::Item => break,
+                                    LifetimeRibKind::AnonymousCreateParameter(binder) => {
+                                        if let Some(earlier_fresh) =
+                                            this.r.extra_lifetime_params_map.get(&binder)
+                                        {
+                                            extra_lifetime_params.extend(earlier_fresh);
+                                        }
+                                    }
+                                    _ => {}
                                 }
                             }
-                            _ => {}
+                            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(
-                        LifetimeRibKind::AnonymousPassThrough(async_node_id, true),
-                        |this| visit::walk_fn_ret_ty(this, &declaration.output),
-                    );
-                } else {
-                    // Add each argument to the rib.
-                    this.with_lifetime_rib(
-                        LifetimeRibKind::AnonymousPassThrough(fn_id, false),
-                        |this| this.resolve_params(&declaration.inputs),
-                    );
-                    this.with_lifetime_rib(
-                        LifetimeRibKind::AnonymousPassThrough(fn_id, true),
-                        |this| visit::walk_fn_ret_ty(this, &declaration.output),
-                    );
-                };
+                        this.with_lifetime_rib(
+                            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),
+                        );
 
-                // 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(
-                    LifetimeRibKind::AnonymousPassThrough(fn_id, false),
-                    |this| match fn_kind {
-                        FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
-                        FnKind::Closure(_, body) => this.visit_expr(body),
-                    },
-                );
+                        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(
+                                LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+                                |this| this.visit_block(body),
+                            );
 
-                debug!("(resolving function) leaving function");
-                this.in_func_body = previous_state;
+                            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.with_lifetime_rib(
+                            LifetimeRibKind::AnonymousPassThrough(fn_id, true),
+                            |this| visit::walk_fn_ret_ty(this, &declaration.output),
+                        );
+
+                        // 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(
+                            LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+                            |this| this.visit_expr(body),
+                        );
+
+                        debug!("(resolving function) leaving function");
+                        this.in_func_body = previous_state;
+                    }
+                }
             })
         });
         self.diagnostic_metadata.current_function = previous_value;
diff --git a/src/test/ui/issues/issue-37884.stderr b/src/test/ui/issues/issue-37884.stderr
index cd84b6ef484..9e4e56793ca 100644
--- a/src/test/ui/issues/issue-37884.stderr
+++ b/src/test/ui/issues/issue-37884.stderr
@@ -11,7 +11,7 @@ LL | |     }
    |
    = note: expected fn pointer `fn(&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
    |
 LL |     fn next(&'a mut self) -> Option<Self::Item>