Repository: rust-lang/rust
File: compiler/rustc_hir_typeck/src/upvar.rs (Rust)

Code before:
            ty::Closure(def_id, args) => {
                (def_id, UpvarArgs::Closure(args), self.closure_kind(ty).is_none())
            }
            ty::CoroutineClosure(def_id, args) => {
                (def_id, UpvarArgs::CoroutineClosure(args), self.closure_kind(ty).is_none())
            }
            ty::Coroutine(def_id, args) => (def_id, UpvarArgs::Coroutine(args), false),
            ty::Error(_) => {
                // #51714: skip analysis when we have already encountered type errors
                return;
            }
            _ => {
                span_bug!(
                    span,
                    "type of closure expr {:?} is not a closure {:?}",
                    closure_hir_id,
                    ty
                );
            }
        };
        let args = self.resolve_vars_if_possible(args);
        let closure_def_id = closure_def_id.expect_local();

        assert_eq!(self.tcx.hir_body_owner_def_id(body.id()), closure_def_id);

        // Used by `ExprUseVisitor` when collecting closure capture information.
        let closure_fcx = FnCtxt::new(self, self.tcx.param_env(closure_def_id), closure_def_id);

        let mut delegate = InferBorrowKind {
            fcx: &closure_fcx,
            closure_def_id,
            capture_information: Default::default(),
            fake_reads: Default::default(),
        };

        let _ = euv::ExprUseVisitor::new(&closure_fcx, &mut delegate).consume_body(body);

        // There are several curious situations with coroutine-closures where
        // analysis is too aggressive with borrows when the coroutine-closure is
        // marked `move`. Specifically:
        //
        // 1. If the coroutine-closure was inferred to be `FnOnce` during signature
        // inference, then it's still possible that we try to borrow upvars from
        // the coroutine-closure because they are not used by the coroutine body
        // in a way that forces a move. See the test:
        // `async-await/async-closures/force-move-due-to-inferred-kind.rs`.
        //
        // 2. If the coroutine-closure is forced to be `FnOnce` due to the way it
        // uses its upvars (e.g. it consumes a non-copy value), but not *all* upvars
        // would force the closure to `FnOnce`.
        // See the test: `async-await/async-closures/force-move-due-to-actually-fnonce.rs`.

Review comment (suggestion):
This comment feels is odd. It states information which is clearly visible 3 lines down. You could state sth like "We need to create a separate `FnCtxt` for nested bodies"

Creating `FnCtxt`s for nested bodies is also something we normally do, so I don't know if that is that useful either. I think it's fine to just not have a comment here at all 

Code after:
            ty::Closure(def_id, args) => {
                (def_id, UpvarArgs::Closure(args), self.closure_kind(ty).is_none())
            }
            ty::CoroutineClosure(def_id, args) => {
                (def_id, UpvarArgs::CoroutineClosure(args), self.closure_kind(ty).is_none())
            }
            ty::Coroutine(def_id, args) => (def_id, UpvarArgs::Coroutine(args), false),
            ty::Error(_) => {
                // #51714: skip analysis when we have already encountered type errors
                return;
            }
            _ => {
                span_bug!(
                    span,
                    "type of closure expr {:?} is not a closure {:?}",
                    closure_hir_id,
                    ty
                );
            }
        };
        let args = self.resolve_vars_if_possible(args);
        let closure_def_id = closure_def_id.expect_local();

        assert_eq!(self.tcx.hir_body_owner_def_id(body.id()), closure_def_id);

        let closure_fcx = FnCtxt::new(self, self.tcx.param_env(closure_def_id), closure_def_id);

        let mut delegate = InferBorrowKind {
            fcx: &closure_fcx,
            closure_def_id,
            capture_information: Default::default(),
            fake_reads: Default::default(),
        };

        let _ = euv::ExprUseVisitor::new(&closure_fcx, &mut delegate).consume_body(body);

        // There are several curious situations with coroutine-closures where
        // analysis is too aggressive with borrows when the coroutine-closure is
        // marked `move`. Specifically:
        //
        // 1. If the coroutine-closure was inferred to be `FnOnce` during signature
        // inference, then it's still possible that we try to borrow upvars from
        // the coroutine-closure because they are not used by the coroutine body
        // in a way that forces a move. See the test:
        // `async-await/async-closures/force-move-due-to-inferred-kind.rs`.
        //
        // 2. If the coroutine-closure is forced to be `FnOnce` due to the way it
        // uses its upvars (e.g. it consumes a non-copy value), but not *all* upvars
        // would force the closure to `FnOnce`.
        // See the test: `async-await/async-closures/force-move-due-to-actually-fnonce.rs`.
        //